This pipeline was created using the following resources:
Within the RStudio file (.rmd), each code chunk can
be executed by clicking the Run button within each
chunk or by placing the cursor inside it and pressing
Cntrl+Shift+Enter.
After installing R and RStudio, the following
Bioconductor R packages are necessary for processing RNASeq raw data,
conducting differential expression analysis and data visualization:
For installing packages, execute the code on the
Installation section in the corresponding Bioconductor
page.
For instance, for installing DESeq2:
if (!require("BiocManager", quietly = TRUE))
install.packages("BiocManager")
BiocManager::install("DESeq2")
The remaining packages are part of the Comprehensive R Archive
Network (CRAN), which is the official R packages repository. These can
be installed in RStudio by going to Tools →
Install Packages and in the Install
from option select Repository (CRAN), followed
by specifying the intended packages:
- ggplot2
- Data visualization and export options
- ggalt
- Adds extra data visualization flexibility
- ggrepel
- Adds extra data visualization flexibility
- textshaping
- Necessary for EnhancedVolcano package
- tidyverse
- Data processing and visualization
- RColorBrewer
- Color schemes for data visualization
- circlize
- Necessary for ColorRamp scheme in heatmap data
visualization
- pheatmap
- Basic heatmap data visualization
After installing every required package, these libraries should
be loaded into RStudio so that their commands and functions are
available to use. To do so, enter:
#Loading libraries
library("DESeq2")
library("edgeR")
library("AnnotationDbi")
library("org.Hs.eg.db")
library("ggplot2")
library("ggalt")
library("ggrepel")
library("textshaping")
library("tidyverse")
library("RColorBrewer")
library("circlize")
library("pheatmap")
library("ComplexHeatmap")
library("EnhancedVolcano")
Note: Libraries should always be re-loaded when
re-opening the script.
Afterwards, open the raw count data file in RStudio. This file is a
table that results from mapping the sequencing reads to a reference
genome and displays the number of reads assigned to each gene, in each
sample. This tab-delimited file contains a header row with each sample
name and each row name represents a unique Ensembl gene ID (ENSG).
In this work, the file “2D_counts.txt” was used for
differential gene expression analysis of 2D Native
hASCs vs 2D Glycoengineered hASCs. For
assessing the impact of cell-cell tethering in the transcriptome,
2D Glycoengineered hASCs vs 3D
Cellgels samples were pooled into
“2Dv3D_counts.txt”.
For ease of comprehension, each function is described
line-by-line in commented descriptions. For further information, please
refer to each package’s vignette containing the comprehensive command
list.
First, RNASeq analysis in 2D conditions was
conducted:
#Reads count table and assigns it to a variable called "Counts".
Counts <- read.table("2D_counts.txt", header = TRUE, row.names = 1, sep ="\t")
Counts
Note: Before starting the analysis, confirm
that the raw counts table contains the actual unprocessed reads
and not the output of a previous DESeq2 workflow. Raw count values are
stored as integers, whereas normalized counts are decimals numbers.
DESeq2 differential expression analysis can only be conducted on raw
unprocessed counts.
#Creates data frame called "coldata" that assigns experimental conditions ("2DControl" or "2DGly") to each sample and stores this factor in the "treatment" column. Also renames the original sample names in the .bam file to shorter and convenient IDs.
coldata <- DataFrame(id = c("2DC1", "2DC2", "2DC3", "2DC4", "2DC5", "2DG1", "2DG2", "2DG3", "2DG4", "2DG5"), treatment= factor(c(rep("2DControl", times = 5), rep("2DGly", times = 5)), levels = c("2DControl", "2DGly")))
#Saves the formatted counts table to a .txt file.
write.table(Counts, file = "2D_counts_v2.txt", sep = "\t", quote=FALSE, col.names = TRUE)
coldata
DataFrame with 10 rows and 2 columns
id treatment
<character> <factor>
1 2DC1 2DControl
2 2DC2 2DControl
3 2DC3 2DControl
4 2DC4 2DControl
5 2DC5 2DControl
6 2DG1 2DGly
7 2DG2 2DGly
8 2DG3 2DGly
9 2DG4 2DGly
10 2DG5 2DGly
Next, a pre-filtering strategy is applied to
the Counts table. Before proceeding with differential
expression analysis, it is important to filter out genes that
consistently present extremely low expression. This reduces multiple
testing burden and helps in increasing the statistical power of the
analysis, while keeping genes of interest.
Herein, counts per million (CPM) are used for
pre-filtering rather than raw counts,
as CPM accounts for differences in library
sizes (i.e., sequencing depth = total number of counts) across
samples, ensuring a more robust comparison. For instance, if samples
yielded uneven library sizes (e.g. 15 M vs 40 M), a filtering criteria
solely based on raw counts would not avoid favoring genes that are
expressed in the larger library. CPM is calculated
through edgeR as the raw counts divided by
library size and multiplied by one million.
Note: CPM calculation through
edgeR package is more sophisticated than manually
applying the formula as it also automatically corrects for library
composition using calcNormFactors.
As a rule of thumb, for library sizes of about 20 M
reads, a CPM = 0.5 is used as it corresponds to a
raw count of 10 - 15.
Note: To view the library size for each sample
enter:
library_size <- colSums(Counts)
library_size.df <- as.data.frame(library_size)
rownames(library_size.df) <- coldata$id
library_size.df
#Cross-checking whether a CPM threshold of 0.5 corresponds to approximately 10 - 15 counts in these samples.
myCPM_colnames = c("C1", "C2", "C3", "C4", "C5", "G1", "G2", "G3", "G4", "G5")
myCPM <- cpm(Counts) #edgeR calculates the Counts Per Million (CPM) values for the Raw Counts object.
plot(myCPM[,1], Counts[,1], xlab="CPM", ylab="Raw Counts", main=paste("Sample", myCPM_colnames[1]),
ylim=c(0,50), xlim=c(0,3))
#Adds reference lines at x = 0.5 CPM and y = 10 Raw Counts
abline(v=0.5) + abline(h=10)

Considering library sizes in this dataset are on the order of 20 M, a
threshold for genes with CPM > 0.5 was established.
An additional requirement for expression in 3 or more
libraries is used, as each group contains 5 replicates.
Applying a stringent pre-filtering threshold ensures a
more reliable and robust analysis. This criteria eliminates genes that
are unlikely to be relevant due to (i) inconsistent
reads across different samples, and (ii) increased fold
change and variance associated with extremely low counts. In addition,
this setup ensures that a gene will be retained even if it is only
expressed in one experimental condition.
#Pre-filtering Counts to CPM > 0.5 in at least 3 different samples
keepCPM <- rowSums(cpm(Counts) > 0.5) >= 3
CPMCounts <- Counts[keepCPM,]
nrow(Counts) #61552 = Total number of mapped genes
nrow(CPMCounts) #14194 = Number of genes after pre-filtering
#Running DESeq2 analysis
ddsCPM <- DESeqDataSetFromMatrix(countData = CPMCounts, colData = coldata, design = ~treatment)
ddsCPM <- DESeq(ddsCPM)
resddsCPM <- results(ddsCPM)
resddsCPM #Show DESeq2 results table
log2 fold change (MLE): treatment 2DGly vs 2DControl
Wald test p-value: treatment 2DGly vs 2DControl
DataFrame with 14194 rows and 6 columns
baseMean log2FoldChange lfcSE stat pvalue padj
<numeric> <numeric> <numeric> <numeric> <numeric> <numeric>
ENSG00000160072 217.7990 0.2211119 0.138383 1.597820 0.1100829 0.2225651
ENSG00000142611 66.1508 -0.4467950 0.178257 -2.506466 0.0121945 0.0393714
ENSG00000225630 525.1312 0.0389046 0.147856 0.263125 0.7924545 0.8773250
ENSG00000131584 42.3183 0.4723784 0.288730 1.636059 0.1018273 0.2098193
ENSG00000169972 130.7999 0.0926638 0.124668 0.743283 0.4573102 0.6180456
... ... ... ... ... ... ...
ENSG00000210196 52.4841 -0.1962727 0.203209 -0.965866 0.334111 0.499162
ENSG00000276256 89.2431 0.1866894 0.135644 1.376321 0.168722 0.306774
ENSG00000273748 44.4494 0.1237211 0.194458 0.636234 0.524624 0.677302
ENSG00000276197 12.6270 0.0673584 0.571645 0.117833 0.906200 0.946688
ENSG00000271254 50.1216 -0.1487663 0.201549 -0.738116 0.460444 0.620557
#Output DESeq2 Normalized Counts - Necessary for submitting RNASeq datasets to the SRA repository.
normalized_counts <- counts(ddsCPM, normalized=TRUE)
write.table(normalized_counts, file = "2D_normalizedcounts.txt", sep = "\t", quote=FALSE, col.names = TRUE)
Next, to improve interpretability, it is useful to convert the
mapped ENSEMBL IDs (e.g., ENSG00000115414) to the more
recognizable Gene Symbols (e.g., FN1 for the
Fibronectin gene).
#Adds a new column "geneID" to the results table containing the corresponding Gene Symbols to each row
GeneIDs <- mapIds(org.Hs.eg.db,
keys = row.names(resddsCPM),
keytype = "ENSEMBL",
column = "SYMBOL")
ENS_geneIDs <- stack(GeneIDs)
resddsCPM$geneID <- ENS_geneIDs$values
resddsCPM #Show the updated DESeq2 results table with the new geneID column
log2 fold change (MLE): treatment 2DGly vs 2DControl
Wald test p-value: treatment 2DGly vs 2DControl
DataFrame with 14194 rows and 7 columns
baseMean log2FoldChange lfcSE stat pvalue padj geneID
<numeric> <numeric> <numeric> <numeric> <numeric> <numeric> <character>
ENSG00000160072 217.7990 0.2211119 0.138383 1.597820 0.1100829 0.2225651 ATAD3B
ENSG00000142611 66.1508 -0.4467950 0.178257 -2.506466 0.0121945 0.0393714 PRDM16
ENSG00000225630 525.1312 0.0389046 0.147856 0.263125 0.7924545 0.8773250 MTND2P28
ENSG00000131584 42.3183 0.4723784 0.288730 1.636059 0.1018273 0.2098193 ACAP3
ENSG00000169972 130.7999 0.0926638 0.124668 0.743283 0.4573102 0.6180456 PUSL1
... ... ... ... ... ... ... ...
ENSG00000210196 52.4841 -0.1962727 0.203209 -0.965866 0.334111 0.499162 NA
ENSG00000276256 89.2431 0.1866894 0.135644 1.376321 0.168722 0.306774 LOC389831
ENSG00000273748 44.4494 0.1237211 0.194458 0.636234 0.524624 0.677302 NA
ENSG00000276197 12.6270 0.0673584 0.571645 0.117833 0.906200 0.946688 NA
ENSG00000271254 50.1216 -0.1487663 0.201549 -0.738116 0.460444 0.620557 LOC102724250
Note: Gene symbols (‘geneID’ column) with
NA values are typically pseudogenes, some of those associated
with producing antisense RNA transcripts. Not every ENSEMBL Gene ID
corresponds to a HGNC Gene Symbol entry.
#Output full results: Normalized counts + DESeq2 results table
results_sum <- cbind(normalized_counts, resddsCPM)
#write.csv(results_sum, file = "2D_full_results.csv", quote=FALSE, col.names = TRUE) #.CSV alternative to upload data
write.table(results_sum, file = "2D_full_results.txt", sep = "\t", quote=FALSE, col.names = TRUE) #.TXT for better data fetching
After DESeq2 processing, differential expression analysis of
genes can be conducted. In this work, genes are considered to be
Differentially Expressed Genes (DEGs) if they exhibit
an adjusted p-value < 0.05 (padj,
Benjamini-Hochberg procedure for multiple testing correction) and
present log2(fold change) > 1 or <
-1.
Specifically, a log2(fold change) > 1 translates
into an > 2-fold upregulated gene expression,
whereas a log2(fold change) < -1 indicates a
< 0.5 fold downregulation. By combining both of
these thresholds, this robust criteria provides greater specificity for
identifying genes that are not only statistically significant, but are
also more likely to be biologically relevant.
#Analysis of DEGs distribution for Donut Plot
resddsCPM <- resddsCPM[!is.na(resddsCPM$padj), ] #Clean-up of genes containing 'NA' in 'padj' column. This occurs in genes filtered out by DESeq2 through automatic independent filtering or containing a sample with an extreme count outlier, as detected by Cook's distance.
sigs <- resddsCPM[resddsCPM$padj < 0.05,] #Creates a subset of genes that meet the padj < 0.05 threshold.
sigsALL <- sigs[abs(sigs$log2FoldChange) > 1,] #Total DEGs, use of absolute log2fold change values ('abs').
sigsUP <- sigs[sigs$log2FoldChange > 1,] #Upregulated DEGs.
sigsDOWN <- sigs[sigs$log2FoldChange < -1,] #Downregulated DEGs.
#Summary
#dim(resddsCPM) #Total genes = 14193
#dim(sigs) #Total statistically significant genes = 4692
#dim(sigsALL) #Total DEGs = 568
#dim(sigsUP) #Upregulated DEGs = 180
#dim(sigsDOWN) #Downregulated DEGs = 388
#Output DEGs
sigsALL.df <- as.data.frame(sigsALL)
sigsALL.df$symbol <- mapIds(org.Hs.eg.db, keys = rownames(sigsALL.df), keytype = "ENSEMBL", column = "SYMBOL") #Alternative way to add Gene Symbols to each row, available upon conversion to a data.frame object.
write.csv(sigsALL.df, "2D_DEGs.csv", quote = FALSE, col.names = TRUE)
#Output Volcano table
write.csv(resddsCPM, "2D_Volcano.csv", quote = FALSE, col.names = TRUE)
Next, the quality of the RNASeq dataset can be validated by
plotting the per-gene dispersion estimates versus the mean
expression. The visualization of this plot
(plotDispEsts) allows for rapidly checking whether the
fitted mean-dispersion relationship (red trend
line) shows an appropriate fit to the data and
ensure the validity of differential testing assumptions
in downstream analysis.
#Plot fitted mean-dispersion relationship
plotDispEsts(ddsCPM)

In addition, it is important to perform a scatterplot of the
biological coefficient of variation
(BCV) against the average abundance of each gene. A
BCV plot provides further visualization of the
biological variability across samples in terms of gene
expression, and whether this variance is adequate for fitting.
As found below, the common dispersion (Disp) is
0.01331 and the BCV (square root of
Disp) is 0.1154. Typically, the
asymptotic value for BCV tends to be within the
0.05 - 0.2 range for cell line experiments or
genetically identical mice, whereas larger values (>
0.3) can be found in human subjects datasets. As a result, this
BCV analysis further confirms the validity of the
dataset for subsequent downstream analysis, as it will be demonstrated
below.
#edgeR processing for fitting and calculations
condition = factor(c(rep("2DControl", times = 5), rep("2DGly", times = 5)))
dgeGlm <- DGEList(counts = CPMCounts, group = condition)
str(dgeGlm)
names(dgeGlm)
dgeGlm[["samples"]]
#Calculate common dispersion (Disp) and biological coefficient of variation (BCV)
design <- model.matrix(~condition)
dgeGlmComDisp <- estimateGLMCommonDisp(dgeGlm, design, verbose = TRUE) #Disp = 0.01331, BCV = 0.1154
Disp = 0.01331 , BCV = 0.1154
#Plotting BCV scatterplot
dgeGlmTrendDisp <- estimateGLMTrendedDisp(dgeGlmComDisp, design)
dgeGlmTagDisp <- estimateGLMTagwiseDisp(dgeGlmTrendDisp, design)
plotBCV(dgeGlmTagDisp)

RNASeq datasets often contain thousands of genes across multiple
samples, making it extremely complex to detect and analyze patterns of
gene expression data. In this context, Principal Component
Analysis (PCA) transforms data into a set of
uncorrelated variables (i.e., principal components), which is useful for
reducing data dimensionality, providing a blind and
unbiased assessment of gene expression patterns across
multiple samples and conditions. PC1 describes the most variation within
the data, PC2 the second most, and so forth.
Therefore, PCA is highly valuable for
(i) identifying gene expression trends
(e.g., confirming the biological relevance of the treatment/disease or
experimental condition), (ii) identifying
clusters of samples and their relationships, and
(iii) screening out any potential
outliers or batch effects. Visualizing
these effects assists in confirming the hypothesis tested in further
DEGs downstream analysis.
To create a PCA plot, first a vst()
(i.e., variance-stabilizing transformation) function should be
applied to remove the dependence of the variance on the mean. This is
because analysis of multi-dimensional data (such as PCA) works best for
homoskedastic data (i.e., consistent variability), whereas in RNASeq
data variance increases with the mean values. Unlike the other DESeq2
function (i.e., rlog()) function for this purpose,
vst() is more sensitive to size factor and also
normalizes with respect to library size.
#Output 2D PCA Plot
vsdata <- vst(ddsCPM, blind = FALSE) #Apply variance-stabilizing transformation to DESeq object 'ddsCPM'
#By default both these functions are **blind** to the sample design formula given to DESeq2 in DESeqDataSetFromMatrix(), however this is not appropriate if one expects large differences in counts explained by differences in experimental design. In such cases, the blind parameter should be set to 'FALSE' as recommended in DESeq2 vignette.
#plotPCA(vsdata, intgroup = "treatment") #Preview PC1 and PC2 % for correct axis labeling.
PCAraw <- plotPCA(vsdata, intgroup = "treatment") #Create a PCA plot using 'vsdata' and groups it by 'treatment'.
group.colors <- c("#619CFF","#00C19F") #Vector containing color codes to be used in each group.
new_pca <- ggplot(PCAraw[["data"]], #Create a ggplot using 'data' data.frame within 'PCAraw' object.
aes(PC1, PC2, color=group)) + #Construct aesthetic mapping using PC1 and PC2.
scale_color_manual(values = group.colors) + #Specify a vector of colors.
geom_point(size = 2.5) + #Change marker size.
xlab("PC1 (79%)") + #Text used for X axis.
ylab("PC2 (9%)") + #Text used for Y axis.
ylim(-10, 10) + #Lower/upper limits for Y axis.
xlim(-12, 12) + #Lower/upper limits for X axis.
theme_grey() + #Set a grey background with white gridlines.
theme(axis.title.x = element_text(size = 14), #Customize size and style of axis titles and text.
axis.title.y = element_text(size = 14),
axis.text.x = element_text(size = 12, face = "bold"),
axis.text.y = element_text(size = 12, face = "bold"))
new_pca
ggsave("2D_PCA.svg", new_pca, dpi = 600, width = 2.6, height = 2, units = "in", scale = 2) #Exports plot in .svg

Apart from PCA, another important analysis to
perform is to determine whether intergroup variability
- which represents differences between experimental conditions in
comparison with control conditions - is greater than the
intragroup variability, representing technical or
biological variance. This is achieved by calculating
distance as represented by correlation across samples,
typically using the Pearson’s correlation plot.
Pearson’s coefficient reflects the linear
relationship between 2 variables accounting for differences in mean and
standard deviation. For instance, the more similar the gene
expression profiles for all transcripts are between two
samples, the higher the correlation coefficient will
be. These coefficients are calculated between all samples and are then
visualized as a heatmap.
Similar to PCA, the Pearson’s correlation plot
provides an overview of the overall strength of the biological
effect of the experiment, assessing whether replicates and
different conditions group together, as well as identify outliers that
were not excluded during upstream steps (e.g., sample labeling or
genomic alignment).
#Output 2D Pearson's Correlation Plot
vsdata <- vst(ddsCPM, blind = FALSE) #Apply variance-stabilizing transformation.
sampleDists <- cor(method = "pearson", assay(vsdata)) #Calculate Pearson correlation coefficients.
sampleDistMatrix <- as.matrix(sampleDists) #Convert to matrix format.
rownames(sampleDistMatrix) <- paste(vsdata$id) #Label Sample names.
colnames(sampleDistMatrix) <- paste(vsdata$id) #Label Sample names.
colors <- colorRampPalette(brewer.pal(9, "Blues"))(255) #Color palette range for heatmap visualization.
SampleDistance = pheatmap(sampleDistMatrix, col=colors) #Generate heatmap with 'sampleDistMatrix' and 'colors' inputs.
SampleDistance #ggsave("SD_2D_Pearson.svg", SampleDistance, dpi = 600, width = 2.55, height = 2, units = "in", scale = 2)

#Alternative: Euclidean Distances Correlation Plot, as described in DESeq2 vignette
sampleDists_Euclidean <- dist(t(assay(vsdata))) #Calculate Pearson correlation coefficients.
sampleDistMatrix_Euclidean <- as.matrix(sampleDists_Euclidean) #Convert to matrix format.
rownames(sampleDistMatrix_Euclidean) <- paste(vsdata$id) #Label Sample names.
colnames(sampleDistMatrix_Euclidean) <- paste(vsdata$id) #Label Sample names.
colors <- colorRampPalette(rev(brewer.pal(9, "Blues")))(255) #Color palette range for heatmap visualization.
SampleDistancevignette = pheatmap(sampleDistMatrix_Euclidean, #Generate heatmap with 'sampleDistMatrix' and 'colors' inputs.
clustering_distance_rows=sampleDists_Euclidean, #Clustering by Euclidean distance.
clustering_distance_cols=sampleDists_Euclidean, #Clustering by Euclidean distance.
col=colors)
SampleDistancevignette #ggsave("2D_SD.svg", SampleDistancevignette, dpi = 600, width = 2.55, height = 2, units = "in", scale = 2)

Next, a Volcano plot can be assembled to
provide a general overview of the gene expression profiles of 2D Native
hASCs vs 2D Glycoengineered hASCs. Volcano plots
provide a clear and intuitive visualization of statistical
significance and the extent of fold changes
for every gene detected. Here, each gene is plotted with their
statistical significance (adjusted p-values on the y-axis) agaisnt the
fold change (log2 fold change on the x-axis).
Then, a threshold is set to highlight genes that are
differentially expressed (DEGs), as represented in the
plot in the form of dashed lines. As aforementioned, this work considers
as DEGs genes that present an adjusted p-value
< 0.05 and log2(fold change) > 1 or
< -1. This combination of significance and
fold change information allows researchers to efficiently
identify and prioritize genes
of interest for further investigation. In addition,
Volcano plots can also assist in screening out genes
with high statistical significance but low fold changes, which may be
significant due to large sample sizes but may not have substantial
biological relevance.
#Output 2D Volcano plot with specific Genes of Interest labelled
resddsCPM.df <- as.data.frame(resddsCPM) #Convert DESeq2 results object to a data frame.
#Create custom key-value pairs for 'Up', 'Down', 'Non-DEG' expression. Achieved using nested 'ifelse' statements.
keyvals <- ifelse(resddsCPM$padj > 0.05, 'grey30', #If padj > 0.05 assign grey color.
ifelse(resddsCPM$log2FoldChange < -1, 'royalblue', #If log2foldchange < -1, assign blue color.
ifelse(resddsCPM$log2FoldChange > 1, 'firebrick3', #If log2foldchange > 1, assign red color.
'grey30'))) #Other values assigned grey color.
#Rename elements in 'keyvals' vector:
names(keyvals)[keyvals == 'firebrick3'] <- 'Up' #Assign 'Up' to elements in red.
names(keyvals)[keyvals == 'grey30'] <- 'Non-DEG' #Assign 'Non-DEG' to elements in red.
names(keyvals)[keyvals == 'royalblue'] <- 'Down' #Assign 'Up' to elements in red.
#Define vector containing Gene Symbols to highlight in plot
selected = c("PTGS2", "KRT19", "CXCL1", "SLC7A11", "NDNF", "PGD", "VCAM1", "GPC1", "ANGPT1", "GDF15")
#Volcano plot settings
enhvolc <- EnhancedVolcano(resddsCPM.df, #Create Volcano plot using 'resddsCPM.df'
x = "log2FoldChange", #Column name containing log2(fold change) values.
y = "padj", #Column name containing adjusted p-value values.
#lab = NA, #Uncomment this function for unlabeled genes.
pCutoff = 0.05, #Cut-off threshold for statistical significance.
FCcutoff = 1, #Cut-off threshold for absolute log2(fold change).
title = NULL, #Plot title.
subtitle = NULL, #Plot subtitle.
caption = NULL, #Plot caption.
xlab = bquote(~Log[2]~"(Fold Change)"), #Label for x-axis.
ylab = bquote(~-Log[10] ~ "(" * italic(P[adj]) * ")"), #Label for y-axis.
colAlpha = 0.5, #Alpha for color transparency.
colCustom = keyvals, #Override color scheme (e.g. color by pathway, cell-type or condition).
pointSize = 1, #Size of plotted points.
labSize = 4, #Size of labels for each point.
drawConnectors = TRUE, #Connect labels to each corresponding point by line connectors.
widthConnectors = 0.65, #Line width of connectors.
arrowheads = FALSE, #Draw arrowheads instead of simple line connectors.
boxedLabels = TRUE, #Draw labels within boxes.
directionConnectors = 'both', #Direction to draw connectors (e.g., 'y', 'x' or 'both').
xlim = c(-6, 6), #Limits of x-axis.
ylim = c(0, -log10(10e-255)), #Limits of y-axis.
#Exclude these if not highlighting specific genes
lab = resddsCPM.df$geneID, #Input Gene Symbol column of data.frame object.
selectLab = selected #Vector containing a subset of genes of interest.
)
#Customize axis limits and breaks
p1 <- enhvolc +
ggplot2::coord_cartesian(xlim = c(-6.4, 6.4), #Zoom plot to the specific x-axis limit.
ylim = c(0, 250)) + #Zoom plot to the specific y-axis limit.
ggplot2::scale_x_continuous(breaks=seq(-6, 6, 2)) + #Set spacing of breaks in plot x-axis.
ggplot2::scale_y_continuous(breaks=seq(0, 250, 50)) #Set spacing of breaks in plot y-axis.
p1
ggsave("2D_Volcano_Wide_Label.svg", p1, width = 4.5, height = 2.8, units = "in", scale = 2)

Alternatively, Volcano plots can be customized
via other packages (e.g., ‘ggplot2’) as subplot overlays for
presenting a list of target genes with different shading
specifications.
For instance, overlaying all genes that
match a specific requirement (i.e., all ILs genes).

In addition, it is also possible to assemble a Volcano
plot containing an overlay of genes of
interest on top.

Alternatively, it is possible to assemble a MA
plot, which conveys a similar overview to Volcano
plots. However, this plot lacks the design flexibility that
Volcano plots offer through their dedicated R packages.
#Alternative to Volcano - MA Plot. Less flexibility in customizing the final figure.
MAPlot_dds <- DESeq2::plotMA(resddsCPM, alpha = 0.05, #Set p-value cut-off threshold.
colNonSig = "gray30", #Set color code for Non-DEG.
colSig = "royalblue3", #Set color code for statistically significant.
ylim = c(-7, 7)) #Set y-axis limit.
abline(h = c(1, -1), lty = 2) #Draw horizontal lines at the specified y-axis values, line type - dashed.

Apart from Volcano plots,
Heatmaps provide an important visualization tool in
RNASeq for detecting gene expression trends and highlighting genes with
relevant biological functions. Herein, each sample is assigned to a
column, and each row corresponds to a DEG with
color-coded expression level. Expression values are
typically normalized and transformed (i.e., row
z-scaling) to ensure that genes with varying expression levels
can be compared easily. Heatmaps are usually paired
with hierarchical clustering algorithms (e.g.,
Pearson’s) that group together genes and samples with similar expression
profiles, generating a hierarchical tree-like dendrogram.
Heatmaps are thus useful in RNASeq downstream analysis
for revealing co-expression patterns and
biological functions affected by experimental
conditions.
#Transformation of data for Heatmap
vsdata <- vst(ddsCPM, blind = FALSE) #Apply variance-stabilizing transformation.
vst_mat <- assay(vsdata) #Create matrix with transformed gene expression values.
vst_mat <- vst_mat[rownames(sigsALL.df), ] #Subset matrix to include only DEGS, i.e., rows that match genes listed in 'sigsALL.df'.
Genename <- mapIds(org.Hs.eg.db, #Map Ensembl ID from matrix to Gene Symbol and store in variable 'Genename'.
keys = row.names(vst_mat),
keytype = "ENSEMBL",
column = "SYMBOL")
#Replace NA gene symbols with ENSEMBL IDs in vst_mat.
#(i) Identify which entries in 'Genename' have missing values (NA).
no_symbol_idx <- is.na(Genename)
#(ii) For 'Genename' entries with NA, replace values with original Ensembl ID extracted from 'vst_mat' row names.
Genename[no_symbol_idx] <- row.names(vst_mat)[no_symbol_idx]
#(iii) Convert 'Genename' vector into a single column data.frame, making it suitable for assignment to row names of 'vst_mat'
ENS_geneIDs <- stack(Genename)
#(iv) Replace Ensembl ID entries with Gene Symbols when available, and retains original Ensembl ID if NA.
row.names(vst_mat) <- ENS_geneIDs$values
#Double-check that no DEGs were lost during assignment
#dim(vst_mat) #568 DEGs -> TRUE
#Scale genes z-score by row, as otherwise large values from highly expressed genes would dominate the plot
vst_mat_z <- t(scale(t(vst_mat)))
#Assign column names to each sample
colnames(vst_mat_z) <- c("2DC1", "2DC2", "2DC3", "2DC4", "2DC5", "2DG1", "2DG2", "2DG3", "2DG4", "2DG5")
#Heatmap parameters
col_fun <- colorRamp2(c(-2, 0, 2), #Create segments for the color gradient.
c("#2166AC", "white", "#B2182B")) #Create color gradient with the specified color codes.
lgd_list <- list(title = "Z-score", #Set legend title.
legend_height = unit(2.5, "cm"), #Set height of the legend body.
grid_width = unit(0.4, "cm"), #Set width of each legend grid.
title_position = "topcenter", #Set position of the title.
gap = unit(4, "mm")) #Set gap between heatmap and legend.
#Output full DEGs Heatmap
ht <- Heatmap(vst_mat_z, #Matrix input for heatmap.
col = col_fun, #Set vector of colors for interpolation.
show_column_names = FALSE, #Whether to show column labeling.
show_row_names = FALSE, #Whether to show row labeling.
#row_labels = sigs.df[rownames(vst_mat_z),]$Symbol, #Uncomment to specify row labeling.
row_names_gp = gpar(fontsize = 5), #Set font size for row labeling.
clustering_distance_columns = "pearson", #Set clustering method for column dendrogram.
clustering_distance_rows = "pearson", #Set clustering method for row dendrogram.
#column_labels = colnames(vst_mat_z), #Uncomment for specifying column labeling.
column_names_gp = gpar(fontsize = 5), #Set font size for column labeling.
row_dend_reorder = FALSE, #Whether to apply row dendrogram reordering.
column_dend_reorder = TRUE, #Whether to apply column dendrogram reordering.
show_row_dend = TRUE, #Whether to show row dendrogram clustering.
row_dend_width = unit(10, "mm"), #Set width of row dendrograms.
show_column_dend = FALSE, #Whether to show column dendrogram clustering.
width = unit(2, "in"), #Set heatmap width.
height = unit(10, "in"), #Set heatmap height.
name = "Z-score") #Set title.
#ht
#tiff("2D_Full_Heatmap.tiff", width = 4, height = 10, units = "in", res=600)
#draw(ht)
#dev.off()

Next, it becomes highly valuable to zoom in on
specific gene subsets that are involved in relevant
biological processes. Herein, DEGs related to
extracellular matrix organization,
glycoproteins and secreted factors are
mapped to unveil the impact of the cell surface engineering process on
the transcriptome.
#Create vectors of gene lists
Genelist_ECM = c("ADAMTS15", "WNT16", "WNT2", "WNT9A", "ANGPTL4", "BMP4", "MMRN2", "COL21A1", "COL22A1", "OMD", "TNXB", "THSD4")
Genelist_Glycoproteins = c("ADAMTS15", "APCDD1L", "ABCA6", "ABCA8", "ABCA9", "ABCB6", "ABCC2", "ABCC3", "ATP6V0E2", "BRINP1", "CEBPB", "CD200", "EPHA5", "FAM20A", "GPR137B", "GPR68", "GPRC5A", "GPRC5B", "KCNJ5-AS1", "KITLG", "KIT", "LIF", "LYPD1", "MPL", "NOX4", "SHANK2", "SLITRK4", "ST6GALNAC5", "ST6GAL2", "B3GNT8", "WNT16", "WNT2", "WNT9A", "ADCY4", "AFP", "MGAT4B", "AREG", "ANGPT1", "ANGPTL4", "AGTR1", "AQP1", "ACKR3", "B3GALT2", "B4GALNT1", "BMP4", "CDH18", "CDH6", "CDH8", "CHST6", "CDON", "CEMIP", "CHRM2", "CSGALNACT1", "COL21A1", "COL22A1", "C1RL", "CFHR1", "CNNM4", "ENPP4", "ELAPOR1", "ESM1", "EDNRB", "EFNA5", "EPOR", "GRPR", "GPC1", "GDF15", "GDF6", "HHIP", "HGF", "HMMR", "HSD11B1", "IGSF10", "IGFBP3", "ICAM1", "IFNE", "IL1RL1", "IL20RA", "IL34", "JUP", "LRRN3", "LIPG", "ME1", "MXRA5", "MMRN2", "NDNF", "NETO2", "NOTCH4", "OMD", "PLAT", "PDGFRL", "PLXDC1", "GALNT15", "GALNT3", "POPDC3", "KCNK1", "PCSK6", "PCSK9", "PTGDR", "PTGER3", "PTGS2", "PTPRQ", "PCDHB5", "RAET1E", "RNF128", "RNF150", "SPP1", "SEMA3C", "SEMA3D", "SEMA6D", "PRSS35", "SNAI1", "SLC1A2", "SLC12A9", "SLC14A1", "SLC2A12", "SLC2A5", "SLC24A3", "SLC38A1", "SLC38A4", "SLC4A8", "SLC7A11", "SLC7A14", "TNXB", "TENM4", "THBD", "TRPC6", "TMEM130", "VCAM1")
Genelist_Secreted = c("ADAMTS15", "ABCB6", "CCL26", "CXCL1", "CXCL2", "CXCL3", "CXCL6", "CXCL8", "C1QTNF2", "FAM20A", "HTRA3", "KCNJ5-AS1", "KITLG", "LIF", "WNT16", "WNT2", "WNT9A", "AKR1B10", "AFP", "ANGPT1", "ANGPTL4", "BMP4", "CEMIP", "COL21A1", "COL22A1", "C1RL", "CFHR1", "ESM1", "EDN1", "EPOR", "FABP5", "GPC1", "GDF15", "GDF6", "HHIP", "IGSF10", "IGFBP3", "IFNE", "IL1B", "IL1RL1", "IL34", "LIPG", "MXRA5", "MMRN2", "NDNF", "OMD", "PINLYP", "PLAT", "PDGFRL", "PLXDC1", "PCSK6", "PCSK9", "RAET1E", "SPP1", "SCG5", "SEMA3C", "SEMA3D", "PRSS35", "TNXB", "THSD4")
#Replace here [Genelist_ECM] with the name of the vector for specific genes c("XX", "XY", "XZ")
selected_DEGs <- Genelist_Secreted
#Filters the matrix to retain only the rows that correspond to the genes listed in 'selected_DEGs' vector.
vst_matSelected <- vst_mat[rownames(vst_mat) %in% selected_DEGs, ]
#Double check to ensure that all selected DEGs were retrieved
#dim(vst_mat) #568 DEGs
#dim(vst_matSelected) #60 DEGs
#length(Genelist_Secreted) #60 DEGs
#Apply row z-scaling
vst_matSelected_z <- t(scale(t(vst_matSelected)))
#Assign column names to each sample
colnames(vst_matSelected_z) <- c("2DC1", "2DC2", "2DC3", "2DC4", "2DC5", "2DG1", "2DG2", "2DG3", "2DG4", "2DG5")
#Heatmap parameters
col_fun <- colorRamp2(c(-2, 0, 2), #Create segments for the color gradient.
c("#2166AC", "white", "#B2182B")) #Create color gradient with the specified color codes.
lgd_list <- list(title = "Z-score", #Set legend title.
title_gp = gpar(fontsize = 12), #Set font size for legend title.
legend_height = unit(2.5, "cm"), #Set height of the legend body.
legend_width = unit(5, "cm"), #Set width of the legend body.
grid_width = unit(0.4, "cm"), #Set width of each legend grid.
direction = "horizontal", #Whether scale is 'horizontal' or 'vertical'
title_position = "topcenter", #Set position of the title.
gap = unit(4, "mm")) #Set gap between heatmap and legend.
ht_selected <- Heatmap(vst_matSelected_z, #Matrix input for heatmap.
col = col_fun, #Vector of colors for interpolation.
rect_gp = gpar(col = "grey30", lwd = 0.15), #Border line color and width of each cell.
show_column_names = FALSE, #Whether to show column labeling.
show_row_names = TRUE, #Whether to show row labeling.
row_names_gp = gpar(fontsize = 5), #Set font size for row labeling.
clustering_distance_columns = "pearson", #Set clustering method for column dendrogram.
clustering_distance_rows = "pearson", #Set clustering method for row dendrogram.
#column_labels = colnames(vst_matSelected_z), #Uncomment to specify column labeling.
column_names_gp = gpar(fontsize = 5), #Set font size for column labeling.
row_dend_reorder = FALSE, #Whether to apply row dendrogram reordering.
column_dend_reorder = TRUE, #Whether to apply column dendrogram reordering.
show_row_dend = FALSE, #Whether to show row dendrogram clustering.
row_dend_width = unit(10, "mm"), #Set width of row dendrograms.
show_column_dend = FALSE, #Whether to show column dendrogram clustering.
width = unit(3, "in"), #Set heatmap width.
height = unit(3.5, "in"), #Set heatmap height.
heatmap_legend_param = lgd_list, #Reference object for legend parameters.
#show_heatmap_legend = FALSE, #Uncomment to hide heatmap legend.
name = "Z-score") #Set title.
ht_selected = draw(ht_selected, heatmap_legend_side = "bottom") #Draws heatmap with legend at the bottom position.
#Output settings for each heatmap (W = width, H = height)
#2D_ECM: W = 3 x H = 3.5 | Output svg: W = 5 x H = 5
#2D_Secreted: W = 3 x H = 6.5 | Output svg: W = 4 x H = 4.5
#2D_Glycoproteins: W = 3 x H = 3.5 | Output svg: W = 4 x H = 4.5
svg(filename = "2D_Heatmap_Secreted.svg", width = 4, height = 4.5)
draw(ht_selected, heatmap_legend_side = "bottom")
dev.off()

In large Heatmaps, in order to avoid visual
cluttering by labeling every gene, it is often valuable to label only a
subset of genes.
#Heatmap parameters
col_fun <- colorRamp2(c(-2, 0, 2), #Create segments for the color gradient.
c("#2166AC", "white", "#B2182B")) #Create color gradient with the specified color codes.
lgd_list <- list(title = "Z-score", #Set legend title.
title_gp = gpar(fontsize = 12), #Set font size for legend title.
legend_height = unit(2.5, "cm"), #Set height of the legend body.
legend_width = unit(5, "cm"), #Set width of the legend body.
grid_width = unit(0.4, "cm"), #Set width of each legend grid.
direction = "horizontal", #Whether scale is 'horizontal' or 'vertical'
title_position = "topcenter", #Set position of the title.
gap = unit(4, "mm")) #Set gap between heatmap and legend.
#Create vector with subset of genes to label
Glycoproteins_select_label = c("ANGPT1", "B3GNT8", "MGAT4B", "EDNRB", "NDNF", "ADAMTS15", "ST6GALNAC5", "BMP4", "CDH8", "COL21A1", "IL34", "ICAM1", "NOTCH4", "OMD", "SEMA3D", "VCAM1")
Secreted_select_label = c("WNT2", "WNT16", "CXCL1", "CXCL2", "BMP4", "COL22A1", "EDN1", "GDF6", "IL1B", "CEMIP", "LIPG", "SCG5", "MXRA5", "IFNE", "SPP1", "ANGPT1", "NDNF", "KITLG", "AKR1B10")
#Assign genes subset to a static object for easily switching between plots
Genes_Label = Secreted_select_label
#Identify indices of the row names in the matrix that correspond to the genes listed in the vector 'Genes_Label'
mark_at = which(rownames(vst_matSelected_z) %in% Genes_Label)
#Extract the row names of the matrix that correspond to indices in 'mark_at'. This step is a double-check to ensure that the selected rows do indeed match the original 'Genes_Label' vector.
Genes_DoubleCheck <- rownames(vst_matSelected_z)[mark_at]
#Check whether the two vectors contain the same elements, regardless of their order.
setequal(Genes_DoubleCheck, Genes_Label) #TRUE -> proceed to labeling.
#Note: Use 'Genes_DoubleCheck' object for labeling, because it outputs Gene symbols in the same order as 'mark_at'. This is necessary because 'mark_at' extracts row name numbers, which are automatically ordered numerically in the output vector.
#'anno_mark' function in ComplexHeatmap package enables linking heatmap annotation with customized labels.
foo = anno_mark(at = mark_at, #Numeric index from original matrix.
#link_width = unit(5, "mm"), #Uncomment to specify label link width.
padding = 0.75, #Padding space between neighboring labels.
labels = Genes_DoubleCheck, #Corresponding labels.
labels_gp = gpar(fontsize = 10), #Sets font size.
which = "row") #Whether 'column' or 'row' annotation.
ht_selected_label <- Heatmap(vst_matSelected_z, #Matrix input for heatmap.
col = col_fun, #Vector of colors for interpolation.
rect_gp = gpar(col = "grey30", lwd = 0.15), #Border line color and width of each cell.
show_column_names = FALSE, #Whether to show column labeling.
show_row_names = FALSE, #Whether to show row labeling.
#row_names_gp = gpar(fontsize = 4), #Uncomment to specify row label font size.
#row_names_side = "left", #Uncomment to specify row label side.
clustering_distance_columns = "pearson", #Set clustering method for column dendrogram.
clustering_distance_rows = "pearson", #Set clustering method for row dendrogram.
row_dend_reorder = FALSE, #Whether to apply row dendrogram reordering.
column_dend_reorder = TRUE, #Whether to apply column dendrogram reordering.
show_row_dend = FALSE, #Whether to show row dendrogram clustering.
show_column_dend = FALSE, #Whether to show column dendrogram clustering.
width = unit(3, "in"), #Set heatmap width.
height = unit(3.5, "in"), #Set heatmap height.
heatmap_legend_param = lgd_list, #Reference object for legend parameters.
name = "Z-score") #Set title.
ht_merge = ht_selected_label + rowAnnotation(mark = foo)
ht_merge = draw(ht_merge, heatmap_legend_side = "bottom", align_heatmap_legend = "heatmap_left") #Note: 'align_heatmap_legend' = 'heatmap_center' position is offset because heatmap has been merged with 'rowAnnotation'.

svg(filename = "2D_Heatmap_Secreted_CompactLabel.svg", width = 4.5, height = 4.5)
dev.off()

LS0tDQp0aXRsZTogIlJOQVNlcSBhbmFseXNpcyAtIFIgUGlwZWxpbmUiDQphdXRob3I6ICJQZWRybyBMYXZyYWRvciINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdA0KICB3b3JkX2RvY3VtZW50OiBkZWZhdWx0DQotLS0NCg0KVGhpcyBwaXBlbGluZSB3YXMgY3JlYXRlZCB1c2luZyB0aGUgZm9sbG93aW5nIHJlc291cmNlczoNCg0KKiBbUl0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvYmluL3dpbmRvd3MvYmFzZS8pDQoqIFtSU3R1ZGlvXShodHRwczovL3Bvc2l0LmNvL2Rvd25sb2FkL3JzdHVkaW8tZGVza3RvcC8pDQoNCldpdGhpbiB0aGUgUlN0dWRpbyBmaWxlICgqKi5ybWQqKiksIGVhY2ggY29kZSBjaHVuayBjYW4gYmUgZXhlY3V0ZWQgYnkgY2xpY2tpbmcgdGhlICoqUnVuKiogYnV0dG9uIHdpdGhpbiBlYWNoIGNodW5rIG9yIGJ5IHBsYWNpbmcgdGhlIGN1cnNvciBpbnNpZGUgaXQgYW5kIHByZXNzaW5nICoqQ250cmwrU2hpZnQrRW50ZXIqKi4NCg0KQWZ0ZXIgaW5zdGFsbGluZyAqUiogYW5kICpSU3R1ZGlvKiwgdGhlIGZvbGxvd2luZyBCaW9jb25kdWN0b3IgUiBwYWNrYWdlcyBhcmUgbmVjZXNzYXJ5IGZvciBwcm9jZXNzaW5nIFJOQVNlcSByYXcgZGF0YSwgY29uZHVjdGluZyBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBhbmFseXNpcyBhbmQgZGF0YSB2aXN1YWxpemF0aW9uOg0KDQoqIFtERVNlcTJdKGh0dHBzOi8vYmlvY29uZHVjdG9yLm9yZy9wYWNrYWdlcy9yZWxlYXNlL2Jpb2MvaHRtbC9ERVNlcTIuaHRtbCkgLSAqRGlmZmVyZW50aWFsIGdlbmUgZXhwcmVzc2lvbiBhbmFseXNpcyoNCiogW2VkZ2VSXShodHRwczovL2Jpb2NvbmR1Y3Rvci5vcmcvcGFja2FnZXMvcmVsZWFzZS9iaW9jL2h0bWwvZWRnZVIuaHRtbCkgLSAqRGlmZmVyZW50aWFsIGdlbmUgZXhwcmVzc2lvbiBhbmFseXNpcyoNCiogW0Fubm90YXRpb25EYmldKGh0dHBzOi8vYmlvY29uZHVjdG9yLm9yZy9wYWNrYWdlcy9yZWxlYXNlL2Jpb2MvaHRtbC9Bbm5vdGF0aW9uRGJpLmh0bWwpIC0gKkdlbmUgSUQgY29udmVyc2lvbioNCiogW29yZy5Icy5lZy5kYl0oaHR0cHM6Ly9iaW9jb25kdWN0b3Iub3JnL3BhY2thZ2VzL3JlbGVhc2UvZGF0YS9hbm5vdGF0aW9uL2h0bWwvb3JnLkhzLmVnLmRiLmh0bWwpIC0gKkdlbm9tZSBhbm5vdGF0aW9uIGRhdGFiYXNlIGZvciBIdW1hbioNCiogW0NvbXBsZXhIZWF0bWFwXShodHRwczovL2Jpb2NvbmR1Y3Rvci5vcmcvcGFja2FnZXMvcmVsZWFzZS9iaW9jL2h0bWwvQ29tcGxleEhlYXRtYXAuaHRtbCkgLSAqQWR2YW5jZWQgaGVhdG1hcCBkYXRhIHZpc3VhbGl6YXRpb24qDQoqIFtFbmhhbmNlZFZvbGNhbm9dKGh0dHBzOi8vYmlvY29uZHVjdG9yLm9yZy9wYWNrYWdlcy9yZWxlYXNlL2Jpb2MvaHRtbC9FbmhhbmNlZFZvbGNhbm8uaHRtbCkgLSAqQWR2YW5jZWQgdm9sY2FubyBwbG90IGRhdGEgdmlzdWFsaXphdGlvbioNCg0KDQpGb3IgaW5zdGFsbGluZyBwYWNrYWdlcywgZXhlY3V0ZSB0aGUgY29kZSBvbiB0aGUgKipJbnN0YWxsYXRpb24qKiBzZWN0aW9uIGluIHRoZSBjb3JyZXNwb25kaW5nIEJpb2NvbmR1Y3RvciBwYWdlLg0KDQpGb3IgaW5zdGFuY2UsIGZvciBpbnN0YWxsaW5nICoqREVTZXEyKio6DQoNCmBgYHtyIFBhY2thZ2UgSW5zdGFsbGF0aW9uLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KaWYgKCFyZXF1aXJlKCJCaW9jTWFuYWdlciIsIHF1aWV0bHkgPSBUUlVFKSkNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJCaW9jTWFuYWdlciIpDQpCaW9jTWFuYWdlcjo6aW5zdGFsbCgiREVTZXEyIikNCmBgYA0KDQoNClRoZSByZW1haW5pbmcgcGFja2FnZXMgYXJlIHBhcnQgb2YgdGhlIENvbXByZWhlbnNpdmUgUiBBcmNoaXZlIE5ldHdvcmsgKENSQU4pLCB3aGljaCBpcyB0aGUgb2ZmaWNpYWwgUiBwYWNrYWdlcyByZXBvc2l0b3J5LiBUaGVzZSBjYW4gYmUgaW5zdGFsbGVkIGluIFJTdHVkaW8gYnkgZ29pbmcgdG8gKipUb29scyoqIOKGkiAqKkluc3RhbGwgUGFja2FnZXMqKiBhbmQgaW4gdGhlICoqSW5zdGFsbCBmcm9tKiogb3B0aW9uIHNlbGVjdCAqKlJlcG9zaXRvcnkgKENSQU4pKiosIGZvbGxvd2VkIGJ5IHNwZWNpZnlpbmcgdGhlIGludGVuZGVkIHBhY2thZ2VzOg0KDQoqIFtnZ3Bsb3QyXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvZ2dwbG90Mi9pbmRleC5odG1sKSAtICpEYXRhIHZpc3VhbGl6YXRpb24gYW5kIGV4cG9ydCBvcHRpb25zKg0KKiBbZ2dhbHRdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9nZ2FsdC9pbmRleC5odG1sKSAtICpBZGRzIGV4dHJhIGRhdGEgdmlzdWFsaXphdGlvbiBmbGV4aWJpbGl0eSoNCiogW2dncmVwZWxdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9nZ3JlcGVsL3ZpZ25ldHRlcy9nZ3JlcGVsLmh0bWwpIC0gKkFkZHMgZXh0cmEgZGF0YSB2aXN1YWxpemF0aW9uIGZsZXhpYmlsaXR5Kg0KKiBbdGV4dHNoYXBpbmddKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy90ZXh0c2hhcGluZy9pbmRleC5odG1sKSAtICpOZWNlc3NhcnkgZm9yIEVuaGFuY2VkVm9sY2FubyBwYWNrYWdlKg0KKiBbdGlkeXZlcnNlXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvdGlkeXZlcnNlL2luZGV4Lmh0bWwpIC0gKkRhdGEgcHJvY2Vzc2luZyBhbmQgdmlzdWFsaXphdGlvbioNCiogW1JDb2xvckJyZXdlcl0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL1JDb2xvckJyZXdlci9pbmRleC5odG1sKSAtICpDb2xvciBzY2hlbWVzIGZvciBkYXRhIHZpc3VhbGl6YXRpb24qDQoqIFtjaXJjbGl6ZV0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2NpcmNsaXplL2luZGV4Lmh0bWwpIC0gKk5lY2Vzc2FyeSBmb3IgQ29sb3JSYW1wIHNjaGVtZSBpbiBoZWF0bWFwIGRhdGEgdmlzdWFsaXphdGlvbioNCiogW3BoZWF0bWFwXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvcGhlYXRtYXAvcGhlYXRtYXAucGRmKSAtICpCYXNpYyBoZWF0bWFwIGRhdGEgdmlzdWFsaXphdGlvbioNCg0KPGJyPg0KQWZ0ZXIgaW5zdGFsbGluZyBldmVyeSByZXF1aXJlZCBwYWNrYWdlLCB0aGVzZSBsaWJyYXJpZXMgc2hvdWxkIGJlIGxvYWRlZCBpbnRvIFJTdHVkaW8gc28gdGhhdCB0aGVpciBjb21tYW5kcyBhbmQgZnVuY3Rpb25zIGFyZSBhdmFpbGFibGUgdG8gdXNlLiBUbyBkbyBzbywgZW50ZXI6DQpgYGB7ciBlY2hvPVQsIHJlc3VsdHM9J2hpZGUnfQ0KI0xvYWRpbmcgbGlicmFyaWVzDQpsaWJyYXJ5KCJERVNlcTIiKQ0KbGlicmFyeSgiZWRnZVIiKQ0KbGlicmFyeSgiQW5ub3RhdGlvbkRiaSIpDQpsaWJyYXJ5KCJvcmcuSHMuZWcuZGIiKQ0KbGlicmFyeSgiZ2dwbG90MiIpDQpsaWJyYXJ5KCJnZ2FsdCIpDQpsaWJyYXJ5KCJnZ3JlcGVsIikNCmxpYnJhcnkoInRleHRzaGFwaW5nIikNCmxpYnJhcnkoInRpZHl2ZXJzZSIpDQpsaWJyYXJ5KCJSQ29sb3JCcmV3ZXIiKQ0KbGlicmFyeSgiY2lyY2xpemUiKQ0KbGlicmFyeSgicGhlYXRtYXAiKQ0KbGlicmFyeSgiQ29tcGxleEhlYXRtYXAiKQ0KbGlicmFyeSgiRW5oYW5jZWRWb2xjYW5vIikNCmBgYA0KDQoqKk5vdGU6KiogTGlicmFyaWVzIHNob3VsZCBhbHdheXMgYmUgcmUtbG9hZGVkIHdoZW4gcmUtb3BlbmluZyB0aGUgc2NyaXB0Lg0KPGJyPg0KPGJyPg0KDQpBZnRlcndhcmRzLCBvcGVuIHRoZSByYXcgY291bnQgZGF0YSBmaWxlIGluIFJTdHVkaW8uIFRoaXMgZmlsZSBpcyBhIHRhYmxlIHRoYXQgcmVzdWx0cyBmcm9tIG1hcHBpbmcgdGhlIHNlcXVlbmNpbmcgcmVhZHMgdG8gYSByZWZlcmVuY2UgZ2Vub21lIGFuZCBkaXNwbGF5cyB0aGUgbnVtYmVyIG9mIHJlYWRzIGFzc2lnbmVkIHRvIGVhY2ggZ2VuZSwgaW4gZWFjaCBzYW1wbGUuIFRoaXMgdGFiLWRlbGltaXRlZCBmaWxlIGNvbnRhaW5zIGEgaGVhZGVyIHJvdyB3aXRoIGVhY2ggc2FtcGxlIG5hbWUgYW5kIGVhY2ggcm93IG5hbWUgcmVwcmVzZW50cyBhIHVuaXF1ZSBFbnNlbWJsIGdlbmUgSUQgKEVOU0cpLg0KDQpJbiB0aGlzIHdvcmssIHRoZSBmaWxlICoqIjJEX2NvdW50cy50eHQiKiogd2FzIHVzZWQgZm9yIGRpZmZlcmVudGlhbCBnZW5lIGV4cHJlc3Npb24gYW5hbHlzaXMgb2YgKioyRCBOYXRpdmUgaEFTQ3MqKiB2cyAqKjJEIEdseWNvZW5naW5lZXJlZCBoQVNDcyoqLiBGb3IgYXNzZXNzaW5nIHRoZSBpbXBhY3Qgb2YgY2VsbC1jZWxsIHRldGhlcmluZyBpbiB0aGUgdHJhbnNjcmlwdG9tZSwgKioyRCBHbHljb2VuZ2luZWVyZWQgaEFTQ3MqKiB2cyAqKjNEIENlbGxnZWxzKiogc2FtcGxlcyB3ZXJlIHBvb2xlZCBpbnRvICoqIjJEdjNEX2NvdW50cy50eHQiKiouDQoNCjxicj4NCioqRm9yIGVhc2Ugb2YgY29tcHJlaGVuc2lvbiwgZWFjaCBmdW5jdGlvbiBpcyBkZXNjcmliZWQgbGluZS1ieS1saW5lIGluIGNvbW1lbnRlZCBkZXNjcmlwdGlvbnMuIEZvciBmdXJ0aGVyIGluZm9ybWF0aW9uLCBwbGVhc2UgcmVmZXIgdG8gZWFjaCBwYWNrYWdlJ3MgdmlnbmV0dGUgY29udGFpbmluZyB0aGUgY29tcHJlaGVuc2l2ZSBjb21tYW5kIGxpc3QuKioNCg0KPGJyPg0KKipGaXJzdCwgUk5BU2VxIGFuYWx5c2lzIGluIDJEIGNvbmRpdGlvbnMgd2FzIGNvbmR1Y3RlZDoqKg0KYGBge3IgUmVhZCAyRCBjb3VudHN9DQojUmVhZHMgY291bnQgdGFibGUgYW5kIGFzc2lnbnMgaXQgdG8gYSB2YXJpYWJsZSBjYWxsZWQgIkNvdW50cyIuDQpDb3VudHMgPC0gcmVhZC50YWJsZSgiMkRfY291bnRzLnR4dCIsIGhlYWRlciA9IFRSVUUsIHJvdy5uYW1lcyA9IDEsIHNlcCA9Ilx0IikNCkNvdW50cw0KYGBgDQoqKk5vdGU6KiogQmVmb3JlIHN0YXJ0aW5nIHRoZSBhbmFseXNpcywgKipjb25maXJtIHRoYXQgdGhlIHJhdyBjb3VudHMgdGFibGUgY29udGFpbnMgdGhlIGFjdHVhbCB1bnByb2Nlc3NlZCByZWFkcyoqIGFuZCBub3QgdGhlIG91dHB1dCBvZiBhIHByZXZpb3VzIERFU2VxMiB3b3JrZmxvdy4gUmF3IGNvdW50IHZhbHVlcyBhcmUgc3RvcmVkIGFzIGludGVnZXJzLCB3aGVyZWFzIG5vcm1hbGl6ZWQgY291bnRzIGFyZSBkZWNpbWFscyBudW1iZXJzLiBERVNlcTIgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYW5hbHlzaXMgY2FuIG9ubHkgYmUgY29uZHVjdGVkIG9uIHJhdyB1bnByb2Nlc3NlZCBjb3VudHMuDQoNCmBgYHtyIEZvcm1hdHMgYW5kIHNhdmVzIDJEIGNvdW50c30NCiNDcmVhdGVzIGRhdGEgZnJhbWUgY2FsbGVkICJjb2xkYXRhIiB0aGF0IGFzc2lnbnMgZXhwZXJpbWVudGFsIGNvbmRpdGlvbnMgKCIyRENvbnRyb2wiIG9yICIyREdseSIpIHRvIGVhY2ggc2FtcGxlIGFuZCBzdG9yZXMgdGhpcyBmYWN0b3IgaW4gdGhlICJ0cmVhdG1lbnQiIGNvbHVtbi4gQWxzbyByZW5hbWVzIHRoZSBvcmlnaW5hbCBzYW1wbGUgbmFtZXMgaW4gdGhlIC5iYW0gZmlsZSB0byBzaG9ydGVyIGFuZCBjb252ZW5pZW50IElEcy4NCmNvbGRhdGEgPC0gRGF0YUZyYW1lKGlkID0gYygiMkRDMSIsICIyREMyIiwgIjJEQzMiLCAiMkRDNCIsICIyREM1IiwgIjJERzEiLCAiMkRHMiIsICIyREczIiwgIjJERzQiLCAiMkRHNSIpLCB0cmVhdG1lbnQ9IGZhY3RvcihjKHJlcCgiMkRDb250cm9sIiwgdGltZXMgPSA1KSwgcmVwKCIyREdseSIsIHRpbWVzID0gNSkpLCBsZXZlbHMgPSBjKCIyRENvbnRyb2wiLCAiMkRHbHkiKSkpDQoNCiNTYXZlcyB0aGUgZm9ybWF0dGVkIGNvdW50cyB0YWJsZSB0byBhIC50eHQgZmlsZS4NCndyaXRlLnRhYmxlKENvdW50cywgZmlsZSA9ICIyRF9jb3VudHNfdjIudHh0Iiwgc2VwID0gIlx0IiwgcXVvdGU9RkFMU0UsIGNvbC5uYW1lcyA9IFRSVUUpDQpgYGANCg0KYGBge3IgU2hvd3MgY29sZGF0YX0NCmNvbGRhdGENCmBgYA0KDQo8YnI+DQpOZXh0LCBhICoqcHJlLWZpbHRlcmluZyoqIHN0cmF0ZWd5IGlzIGFwcGxpZWQgdG8gdGhlICoqQ291bnRzKiogdGFibGUuIEJlZm9yZSBwcm9jZWVkaW5nIHdpdGggZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYW5hbHlzaXMsIGl0IGlzIGltcG9ydGFudCB0byBmaWx0ZXIgb3V0IGdlbmVzIHRoYXQgY29uc2lzdGVudGx5IHByZXNlbnQgZXh0cmVtZWx5IGxvdyBleHByZXNzaW9uLiBUaGlzIHJlZHVjZXMgbXVsdGlwbGUgdGVzdGluZyBidXJkZW4gYW5kIGhlbHBzIGluIGluY3JlYXNpbmcgdGhlIHN0YXRpc3RpY2FsIHBvd2VyIG9mIHRoZSBhbmFseXNpcywgd2hpbGUga2VlcGluZyBnZW5lcyBvZiBpbnRlcmVzdC4NCg0KSGVyZWluLCAqKmNvdW50cyBwZXIgbWlsbGlvbiAoQ1BNKSoqIGFyZSB1c2VkIGZvciAqKnByZS1maWx0ZXJpbmcqKiByYXRoZXIgdGhhbiAqKnJhdyBjb3VudHMqKiwgYXMgKipDUE0qKiBhY2NvdW50cyBmb3IgZGlmZmVyZW5jZXMgaW4gKipsaWJyYXJ5IHNpemVzKiogKGkuZS4sIHNlcXVlbmNpbmcgZGVwdGggPSB0b3RhbCBudW1iZXIgb2YgY291bnRzKSBhY3Jvc3Mgc2FtcGxlcywgZW5zdXJpbmcgYSBtb3JlIHJvYnVzdCBjb21wYXJpc29uLiAqRm9yIGluc3RhbmNlLCBpZiBzYW1wbGVzIHlpZWxkZWQgdW5ldmVuIGxpYnJhcnkgc2l6ZXMgKGUuZy4gMTUgTSB2cyA0MCBNKSwgYSBmaWx0ZXJpbmcgY3JpdGVyaWEgc29sZWx5IGJhc2VkIG9uIHJhdyBjb3VudHMgd291bGQgbm90IGF2b2lkIGZhdm9yaW5nIGdlbmVzIHRoYXQgYXJlIGV4cHJlc3NlZCBpbiB0aGUgbGFyZ2VyIGxpYnJhcnkuKiAqKkNQTSoqIGlzIGNhbGN1bGF0ZWQgdGhyb3VnaCAqKmVkZ2VSKiogYXMgdGhlICoqcmF3IGNvdW50cyBkaXZpZGVkIGJ5IGxpYnJhcnkgc2l6ZSBhbmQgbXVsdGlwbGllZCBieSBvbmUgbWlsbGlvbioqLg0KDQoqKk5vdGU6KiogKipDUE0qKiBjYWxjdWxhdGlvbiB0aHJvdWdoICoqZWRnZVIqKiBwYWNrYWdlIGlzIG1vcmUgc29waGlzdGljYXRlZCB0aGFuIG1hbnVhbGx5IGFwcGx5aW5nIHRoZSBmb3JtdWxhIGFzIGl0IGFsc28gYXV0b21hdGljYWxseSBjb3JyZWN0cyBmb3IgbGlicmFyeSBjb21wb3NpdGlvbiB1c2luZyAqY2FsY05vcm1GYWN0b3JzKi4NCg0KQXMgYSBydWxlIG9mIHRodW1iLCBmb3IgKipsaWJyYXJ5IHNpemVzKiogb2YgYWJvdXQgMjAgTSByZWFkcywgYSAqKkNQTSA9IDAuNSoqIGlzIHVzZWQgYXMgaXQgY29ycmVzcG9uZHMgdG8gYSAqKnJhdyBjb3VudCoqIG9mIDEwIC0gMTUuDQoNCioqTm90ZToqKiBUbyB2aWV3IHRoZSBsaWJyYXJ5IHNpemUgZm9yIGVhY2ggc2FtcGxlIGVudGVyOg0KYGBge3IgU2hvd3MgTGlicmFyeSBzaXplLCBpbmNsdWRlPVRSVUV9DQpsaWJyYXJ5X3NpemUgPC0gY29sU3VtcyhDb3VudHMpDQpsaWJyYXJ5X3NpemUuZGYgPC0gYXMuZGF0YS5mcmFtZShsaWJyYXJ5X3NpemUpDQpyb3duYW1lcyhsaWJyYXJ5X3NpemUuZGYpIDwtIGNvbGRhdGEkaWQNCmxpYnJhcnlfc2l6ZS5kZg0KYGBgDQoNCg0KYGBge3IgQ1BNIFRocmVzaG9sZGluZyBDaGVjaywgcmVzdWx0cz1GQUxTRX0NCiNDcm9zcy1jaGVja2luZyB3aGV0aGVyIGEgQ1BNIHRocmVzaG9sZCBvZiAwLjUgY29ycmVzcG9uZHMgdG8gYXBwcm94aW1hdGVseSAxMCAtIDE1IGNvdW50cyBpbiB0aGVzZSBzYW1wbGVzLg0KbXlDUE1fY29sbmFtZXMgPSBjKCJDMSIsICJDMiIsICJDMyIsICJDNCIsICJDNSIsICJHMSIsICJHMiIsICJHMyIsICJHNCIsICJHNSIpDQpteUNQTSA8LSBjcG0oQ291bnRzKSAjZWRnZVIgY2FsY3VsYXRlcyB0aGUgQ291bnRzIFBlciBNaWxsaW9uIChDUE0pIHZhbHVlcyBmb3IgdGhlIFJhdyBDb3VudHMgb2JqZWN0Lg0KcGxvdChteUNQTVssMV0sIENvdW50c1ssMV0sIHhsYWI9IkNQTSIsIHlsYWI9IlJhdyBDb3VudHMiLCBtYWluPXBhc3RlKCJTYW1wbGUiLCBteUNQTV9jb2xuYW1lc1sxXSksIA0KICAgICB5bGltPWMoMCw1MCksIHhsaW09YygwLDMpKQ0KI0FkZHMgcmVmZXJlbmNlIGxpbmVzIGF0IHggPSAwLjUgQ1BNIGFuZCB5ID0gMTAgUmF3IENvdW50cw0KYWJsaW5lKHY9MC41KSArIGFibGluZShoPTEwKQ0KYGBgDQoNCkNvbnNpZGVyaW5nIGxpYnJhcnkgc2l6ZXMgaW4gdGhpcyBkYXRhc2V0IGFyZSBvbiB0aGUgb3JkZXIgb2YgMjAgTSwgYSB0aHJlc2hvbGQgZm9yIGdlbmVzIHdpdGggKipDUE0gPiAwLjUqKiB3YXMgZXN0YWJsaXNoZWQuIEFuIGFkZGl0aW9uYWwgcmVxdWlyZW1lbnQgZm9yICoqZXhwcmVzc2lvbiBpbiAzIG9yIG1vcmUgbGlicmFyaWVzKiogaXMgdXNlZCwgYXMgZWFjaCBncm91cCBjb250YWlucyA1IHJlcGxpY2F0ZXMuIEFwcGx5aW5nIGEgc3RyaW5nZW50ICoqcHJlLWZpbHRlcmluZyoqIHRocmVzaG9sZCBlbnN1cmVzIGEgbW9yZSByZWxpYWJsZSBhbmQgcm9idXN0IGFuYWx5c2lzLiBUaGlzIGNyaXRlcmlhIGVsaW1pbmF0ZXMgZ2VuZXMgdGhhdCBhcmUgdW5saWtlbHkgdG8gYmUgcmVsZXZhbnQgZHVlIHRvICoqKGkpKiogaW5jb25zaXN0ZW50IHJlYWRzIGFjcm9zcyBkaWZmZXJlbnQgc2FtcGxlcywgYW5kICoqKGlpKSoqIGluY3JlYXNlZCBmb2xkIGNoYW5nZSBhbmQgdmFyaWFuY2UgYXNzb2NpYXRlZCB3aXRoIGV4dHJlbWVseSBsb3cgY291bnRzLiBJbiBhZGRpdGlvbiwgdGhpcyBzZXR1cCBlbnN1cmVzIHRoYXQgYSBnZW5lIHdpbGwgYmUgcmV0YWluZWQgZXZlbiBpZiBpdCBpcyBvbmx5IGV4cHJlc3NlZCBpbiBvbmUgZXhwZXJpbWVudGFsIGNvbmRpdGlvbi4NCg0KDQpgYGB7ciBQcmUtZmlsdGVyaW5nLCBtZXNzYWdlPUZBTFNFLCByZXN1bHRzPUZBTFNFfQ0KI1ByZS1maWx0ZXJpbmcgQ291bnRzIHRvIENQTSA+IDAuNSBpbiBhdCBsZWFzdCAzIGRpZmZlcmVudCBzYW1wbGVzDQprZWVwQ1BNIDwtIHJvd1N1bXMoY3BtKENvdW50cykgPiAwLjUpID49IDMNCkNQTUNvdW50cyA8LSBDb3VudHNba2VlcENQTSxdDQpucm93KENvdW50cykgICAgIzYxNTUyID0gVG90YWwgbnVtYmVyIG9mIG1hcHBlZCBnZW5lcw0KbnJvdyhDUE1Db3VudHMpICMxNDE5NCA9IE51bWJlciBvZiBnZW5lcyBhZnRlciBwcmUtZmlsdGVyaW5nDQpgYGANCg0KYGBge3IgUnVubmluZyBERVNlcTIsIG1lc3NhZ2U9RkFMU0UsIHJlc3VsdHM9VFJVRX0NCiNSdW5uaW5nIERFU2VxMiBhbmFseXNpcw0KZGRzQ1BNIDwtIERFU2VxRGF0YVNldEZyb21NYXRyaXgoY291bnREYXRhID0gQ1BNQ291bnRzLCBjb2xEYXRhID0gY29sZGF0YSwgZGVzaWduID0gfnRyZWF0bWVudCkNCmRkc0NQTSA8LSBERVNlcShkZHNDUE0pDQpyZXNkZHNDUE0gPC0gcmVzdWx0cyhkZHNDUE0pDQpyZXNkZHNDUE0gI1Nob3cgREVTZXEyIHJlc3VsdHMgdGFibGUNCmBgYA0KYGBge3IgT3V0cHV0IE5vcm1hbGl6ZWQgQ291bnRzfQ0KI091dHB1dCBERVNlcTIgTm9ybWFsaXplZCBDb3VudHMgLSBOZWNlc3NhcnkgZm9yIHN1Ym1pdHRpbmcgUk5BU2VxIGRhdGFzZXRzIHRvIHRoZSBTUkEgcmVwb3NpdG9yeS4NCm5vcm1hbGl6ZWRfY291bnRzIDwtIGNvdW50cyhkZHNDUE0sIG5vcm1hbGl6ZWQ9VFJVRSkNCndyaXRlLnRhYmxlKG5vcm1hbGl6ZWRfY291bnRzLCBmaWxlID0gIjJEX25vcm1hbGl6ZWRjb3VudHMudHh0Iiwgc2VwID0gIlx0IiwgcXVvdGU9RkFMU0UsIGNvbC5uYW1lcyA9IFRSVUUpDQpgYGANCg0KPGJyPg0KTmV4dCwgdG8gaW1wcm92ZSBpbnRlcnByZXRhYmlsaXR5LCBpdCBpcyB1c2VmdWwgdG8gY29udmVydCB0aGUgbWFwcGVkICoqRU5TRU1CTCBJRHMqKiAoZS5nLiwgRU5TRzAwMDAwMTE1NDE0KSB0byB0aGUgbW9yZSByZWNvZ25pemFibGUgKipHZW5lIFN5bWJvbHMqKiAoZS5nLiwgRk4xIGZvciB0aGUgRmlicm9uZWN0aW4gZ2VuZSkuIA0KDQpgYGB7ciBBc3NpZ24gR2VuZSBJRHMsIG1lc3NhZ2U9RkFMU0UsIHJlc3VsdHM9VFJVRX0NCiNBZGRzIGEgbmV3IGNvbHVtbiAiZ2VuZUlEIiB0byB0aGUgcmVzdWx0cyB0YWJsZSBjb250YWluaW5nIHRoZSBjb3JyZXNwb25kaW5nIEdlbmUgU3ltYm9scyB0byBlYWNoIHJvdw0KR2VuZUlEcyA8LSBtYXBJZHMob3JnLkhzLmVnLmRiLA0KICAgICAgICAgICAgICBrZXlzID0gcm93Lm5hbWVzKHJlc2Rkc0NQTSksDQogICAgICAgICAgICAgIGtleXR5cGUgPSAiRU5TRU1CTCIsDQogICAgICAgICAgICAgIGNvbHVtbiA9ICJTWU1CT0wiKQ0KRU5TX2dlbmVJRHMgPC0gc3RhY2soR2VuZUlEcykNCnJlc2Rkc0NQTSRnZW5lSUQgPC0gRU5TX2dlbmVJRHMkdmFsdWVzDQpyZXNkZHNDUE0gI1Nob3cgdGhlIHVwZGF0ZWQgREVTZXEyIHJlc3VsdHMgdGFibGUgd2l0aCB0aGUgbmV3IGdlbmVJRCBjb2x1bW4NCmBgYA0KKipOb3RlOioqIEdlbmUgc3ltYm9scyAoJ2dlbmVJRCcgY29sdW1uKSB3aXRoICpOQSogdmFsdWVzIGFyZSB0eXBpY2FsbHkgcHNldWRvZ2VuZXMsIHNvbWUgb2YgdGhvc2UgYXNzb2NpYXRlZCB3aXRoIHByb2R1Y2luZyBhbnRpc2Vuc2UgUk5BIHRyYW5zY3JpcHRzLiBOb3QgZXZlcnkgRU5TRU1CTCBHZW5lIElEIGNvcnJlc3BvbmRzIHRvIGEgSEdOQyBHZW5lIFN5bWJvbCBlbnRyeS4NCg0KYGBge3IgT3V0cHV0IEZ1bGwgUmVzdWx0c30NCiNPdXRwdXQgZnVsbCByZXN1bHRzOiBOb3JtYWxpemVkIGNvdW50cyArIERFU2VxMiByZXN1bHRzIHRhYmxlDQpyZXN1bHRzX3N1bSA8LSBjYmluZChub3JtYWxpemVkX2NvdW50cywgcmVzZGRzQ1BNKQ0KI3dyaXRlLmNzdihyZXN1bHRzX3N1bSwgZmlsZSA9ICIyRF9mdWxsX3Jlc3VsdHMuY3N2IiwgcXVvdGU9RkFMU0UsIGNvbC5uYW1lcyA9IFRSVUUpICMuQ1NWIGFsdGVybmF0aXZlIHRvIHVwbG9hZCBkYXRhDQp3cml0ZS50YWJsZShyZXN1bHRzX3N1bSwgZmlsZSA9ICIyRF9mdWxsX3Jlc3VsdHMudHh0Iiwgc2VwID0gIlx0IiwgcXVvdGU9RkFMU0UsIGNvbC5uYW1lcyA9IFRSVUUpICMuVFhUIGZvciBiZXR0ZXIgZGF0YSBmZXRjaGluZw0KYGBgDQoNCjxicj4NCkFmdGVyIERFU2VxMiBwcm9jZXNzaW5nLCBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBhbmFseXNpcyBvZiBnZW5lcyBjYW4gYmUgY29uZHVjdGVkLiBJbiB0aGlzIHdvcmssIGdlbmVzIGFyZSBjb25zaWRlcmVkIHRvIGJlICoqRGlmZmVyZW50aWFsbHkgRXhwcmVzc2VkIEdlbmVzIChERUdzKSoqIGlmIHRoZXkgZXhoaWJpdCBhbiAqKmFkanVzdGVkIHAtdmFsdWUgPCAwLjA1KiogKCoqcGFkaioqLCBCZW5qYW1pbmktSG9jaGJlcmcgcHJvY2VkdXJlIGZvciBtdWx0aXBsZSB0ZXN0aW5nIGNvcnJlY3Rpb24pIGFuZCBwcmVzZW50ICoqbG9nMihmb2xkIGNoYW5nZSkgPiAxKiogb3IgKio8IC0xKiouDQoNClNwZWNpZmljYWxseSwgYSAqKmxvZzIoZm9sZCBjaGFuZ2UpID4gMSoqIHRyYW5zbGF0ZXMgaW50byBhbiAqKj4gMi1mb2xkIHVwcmVndWxhdGVkIGdlbmUgZXhwcmVzc2lvbioqLCB3aGVyZWFzIGEgKipsb2cyKGZvbGQgY2hhbmdlKSA8IC0xKiogaW5kaWNhdGVzIGEgKio8IDAuNSBmb2xkIGRvd25yZWd1bGF0aW9uKiouIEJ5IGNvbWJpbmluZyBib3RoIG9mIHRoZXNlIHRocmVzaG9sZHMsIHRoaXMgcm9idXN0IGNyaXRlcmlhIHByb3ZpZGVzIGdyZWF0ZXIgc3BlY2lmaWNpdHkgZm9yIGlkZW50aWZ5aW5nIGdlbmVzIHRoYXQgYXJlIG5vdCBvbmx5IHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQsIGJ1dCBhcmUgYWxzbyBtb3JlIGxpa2VseSB0byBiZSBiaW9sb2dpY2FsbHkgcmVsZXZhbnQuDQoNCg0KYGBge3IgT3V0cHV0IERFR3MsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHJlc3VsdHM9RkFMU0V9DQojQW5hbHlzaXMgb2YgREVHcyBkaXN0cmlidXRpb24gZm9yIERvbnV0IFBsb3QNCg0KcmVzZGRzQ1BNIDwtIHJlc2Rkc0NQTVshaXMubmEocmVzZGRzQ1BNJHBhZGopLCBdICNDbGVhbi11cCBvZiBnZW5lcyBjb250YWluaW5nICdOQScgaW4gJ3BhZGonIGNvbHVtbi4gVGhpcyBvY2N1cnMgaW4gZ2VuZXMgZmlsdGVyZWQgb3V0IGJ5IERFU2VxMiB0aHJvdWdoIGF1dG9tYXRpYyBpbmRlcGVuZGVudCBmaWx0ZXJpbmcgb3IgY29udGFpbmluZyBhIHNhbXBsZSB3aXRoIGFuIGV4dHJlbWUgY291bnQgb3V0bGllciwgYXMgZGV0ZWN0ZWQgYnkgQ29vaydzIGRpc3RhbmNlLg0KDQpzaWdzIDwtIHJlc2Rkc0NQTVtyZXNkZHNDUE0kcGFkaiA8IDAuMDUsXSAgICAgICAjQ3JlYXRlcyBhIHN1YnNldCBvZiBnZW5lcyB0aGF0IG1lZXQgdGhlIHBhZGogPCAwLjA1IHRocmVzaG9sZC4NCnNpZ3NBTEwgPC0gc2lnc1thYnMoc2lncyRsb2cyRm9sZENoYW5nZSkgPiAxLF0gICNUb3RhbCBERUdzLCB1c2Ugb2YgYWJzb2x1dGUgbG9nMmZvbGQgY2hhbmdlIHZhbHVlcyAoJ2FicycpLg0Kc2lnc1VQIDwtIHNpZ3Nbc2lncyRsb2cyRm9sZENoYW5nZSA+IDEsXSAgICAgICAgI1VwcmVndWxhdGVkIERFR3MuDQpzaWdzRE9XTiA8LSBzaWdzW3NpZ3MkbG9nMkZvbGRDaGFuZ2UgPCAtMSxdICAgICAjRG93bnJlZ3VsYXRlZCBERUdzLg0KDQojU3VtbWFyeQ0KI2RpbShyZXNkZHNDUE0pICNUb3RhbCBnZW5lcyA9IDE0MTkzDQojZGltKHNpZ3MpICAgICAgI1RvdGFsIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgZ2VuZXMgPSA0NjkyDQojZGltKHNpZ3NBTEwpICAgI1RvdGFsIERFR3MgPSA1NjgNCiNkaW0oc2lnc1VQKSAgICAjVXByZWd1bGF0ZWQgREVHcyA9IDE4MA0KI2RpbShzaWdzRE9XTikgICNEb3ducmVndWxhdGVkIERFR3MgPSAzODgNCg0KI091dHB1dCBERUdzDQpzaWdzQUxMLmRmIDwtIGFzLmRhdGEuZnJhbWUoc2lnc0FMTCkNCnNpZ3NBTEwuZGYkc3ltYm9sIDwtIG1hcElkcyhvcmcuSHMuZWcuZGIsIGtleXMgPSByb3duYW1lcyhzaWdzQUxMLmRmKSwga2V5dHlwZSA9ICJFTlNFTUJMIiwgY29sdW1uID0gIlNZTUJPTCIpICNBbHRlcm5hdGl2ZSB3YXkgdG8gYWRkIEdlbmUgU3ltYm9scyB0byBlYWNoIHJvdywgYXZhaWxhYmxlIHVwb24gY29udmVyc2lvbiB0byBhIGRhdGEuZnJhbWUgb2JqZWN0Lg0Kd3JpdGUuY3N2KHNpZ3NBTEwuZGYsICIyRF9ERUdzLmNzdiIsIHF1b3RlID0gRkFMU0UsIGNvbC5uYW1lcyA9IFRSVUUpDQoNCiNPdXRwdXQgVm9sY2FubyB0YWJsZQ0Kd3JpdGUuY3N2KHJlc2Rkc0NQTSwgIjJEX1ZvbGNhbm8uY3N2IiwgcXVvdGUgPSBGQUxTRSwgY29sLm5hbWVzID0gVFJVRSkNCmBgYA0KDQo8YnI+DQpOZXh0LCB0aGUgcXVhbGl0eSBvZiB0aGUgUk5BU2VxIGRhdGFzZXQgY2FuIGJlIHZhbGlkYXRlZCBieSBwbG90dGluZyB0aGUgKipwZXItZ2VuZSBkaXNwZXJzaW9uIGVzdGltYXRlcyB2ZXJzdXMgdGhlIG1lYW4gZXhwcmVzc2lvbioqLiBUaGUgdmlzdWFsaXphdGlvbiBvZiB0aGlzIHBsb3QgKCoqcGxvdERpc3BFc3RzKiopIGFsbG93cyBmb3IgcmFwaWRseSBjaGVja2luZyB3aGV0aGVyIHRoZSAqKmZpdHRlZCBtZWFuLWRpc3BlcnNpb24gcmVsYXRpb25zaGlwKiogKCpyZWQgdHJlbmQgbGluZSopIHNob3dzIGFuICoqYXBwcm9wcmlhdGUgZml0KiogdG8gdGhlIGRhdGEgYW5kIGVuc3VyZSB0aGUgKip2YWxpZGl0eSoqIG9mIGRpZmZlcmVudGlhbCB0ZXN0aW5nIGFzc3VtcHRpb25zIGluIGRvd25zdHJlYW0gYW5hbHlzaXMuDQoNCmBgYHtyIFBsb3QgRGlzcGVyc2lvbnN9DQojUGxvdCBmaXR0ZWQgbWVhbi1kaXNwZXJzaW9uIHJlbGF0aW9uc2hpcA0KcGxvdERpc3BFc3RzKGRkc0NQTSkNCmBgYA0KDQo8YnI+DQpJbiBhZGRpdGlvbiwgaXQgaXMgaW1wb3J0YW50IHRvIHBlcmZvcm0gYSBzY2F0dGVycGxvdCBvZiB0aGUgKipiaW9sb2dpY2FsIGNvZWZmaWNpZW50IG9mIHZhcmlhdGlvbioqICgqKkJDVioqKSBhZ2FpbnN0IHRoZSBhdmVyYWdlIGFidW5kYW5jZSBvZiBlYWNoIGdlbmUuIEEgKipCQ1YgcGxvdCoqIHByb3ZpZGVzIGZ1cnRoZXIgdmlzdWFsaXphdGlvbiBvZiB0aGUgKipiaW9sb2dpY2FsIHZhcmlhYmlsaXR5KiogYWNyb3NzIHNhbXBsZXMgaW4gdGVybXMgb2YgZ2VuZSBleHByZXNzaW9uLCBhbmQgd2hldGhlciB0aGlzIHZhcmlhbmNlIGlzIGFkZXF1YXRlIGZvciBmaXR0aW5nLg0KDQoNCkFzIGZvdW5kIGJlbG93LCB0aGUgY29tbW9uIGRpc3BlcnNpb24gKCoqRGlzcCoqKSBpcyAqKjAuMDEzMzEqKiBhbmQgdGhlICoqQkNWKiogKHNxdWFyZSByb290IG9mICoqRGlzcCoqKSBpcyAqKjAuMTE1NCoqLiBUeXBpY2FsbHksIHRoZSBhc3ltcHRvdGljIHZhbHVlIGZvciAqKkJDVioqIHRlbmRzIHRvIGJlIHdpdGhpbiB0aGUgKiowLjA1IC0gMC4yKiogcmFuZ2UgZm9yIGNlbGwgbGluZSBleHBlcmltZW50cyBvciBnZW5ldGljYWxseSBpZGVudGljYWwgbWljZSwgd2hlcmVhcyBsYXJnZXIgdmFsdWVzICgqKj4gMC4zKiopIGNhbiBiZSBmb3VuZCBpbiBodW1hbiBzdWJqZWN0cyBkYXRhc2V0cy4gQXMgYSByZXN1bHQsIHRoaXMgKipCQ1YqKiBhbmFseXNpcyBmdXJ0aGVyIGNvbmZpcm1zIHRoZSB2YWxpZGl0eSBvZiB0aGUgZGF0YXNldCBmb3Igc3Vic2VxdWVudCBkb3duc3RyZWFtIGFuYWx5c2lzLCBhcyBpdCB3aWxsIGJlIGRlbW9uc3RyYXRlZCBiZWxvdy4NCg0KDQpgYGB7ciBlZGdlUiBQcm9jZXNzaW5nIGFuZCBCQ1YgUGxvdCwgbWVzc2FnZT1GQUxTRSxlY2hvPVRSVUUsIHJlc3VsdHM9J2hpZGUnfQ0KI2VkZ2VSIHByb2Nlc3NpbmcgZm9yIGZpdHRpbmcgYW5kIGNhbGN1bGF0aW9ucw0KY29uZGl0aW9uID0gZmFjdG9yKGMocmVwKCIyRENvbnRyb2wiLCB0aW1lcyA9IDUpLCByZXAoIjJER2x5IiwgdGltZXMgPSA1KSkpDQpkZ2VHbG0gPC0gREdFTGlzdChjb3VudHMgPSBDUE1Db3VudHMsIGdyb3VwID0gY29uZGl0aW9uKQ0Kc3RyKGRnZUdsbSkNCm5hbWVzKGRnZUdsbSkNCmRnZUdsbVtbInNhbXBsZXMiXV0NCmBgYA0KDQpgYGB7ciBCQ1YgdmFsdWUgYW5kIEJDViBQbG90LCBlY2hvPVRSVUV9DQojQ2FsY3VsYXRlIGNvbW1vbiBkaXNwZXJzaW9uIChEaXNwKSBhbmQgYmlvbG9naWNhbCBjb2VmZmljaWVudCBvZiB2YXJpYXRpb24gKEJDVikNCmRlc2lnbiA8LSBtb2RlbC5tYXRyaXgofmNvbmRpdGlvbikNCmRnZUdsbUNvbURpc3AgPC0gZXN0aW1hdGVHTE1Db21tb25EaXNwKGRnZUdsbSwgZGVzaWduLCB2ZXJib3NlID0gVFJVRSkgI0Rpc3AgPSAwLjAxMzMxLCBCQ1YgPSAwLjExNTQNCg0KDQojUGxvdHRpbmcgQkNWIHNjYXR0ZXJwbG90DQpkZ2VHbG1UcmVuZERpc3AgPC0gZXN0aW1hdGVHTE1UcmVuZGVkRGlzcChkZ2VHbG1Db21EaXNwLCBkZXNpZ24pDQpkZ2VHbG1UYWdEaXNwIDwtIGVzdGltYXRlR0xNVGFnd2lzZURpc3AoZGdlR2xtVHJlbmREaXNwLCBkZXNpZ24pDQpwbG90QkNWKGRnZUdsbVRhZ0Rpc3ApDQpgYGANCg0KDQpgYGB7ciBFZGdlUiBTbWVhclBsb3QsIGluY2x1ZGU9RkFMU0V9DQojZWRnZVIgYWx0ZXJuYXRpdmUgdG8gVm9sY2FubyBQbG90DQpmaXQgPC0gZ2xtRml0KGRnZUdsbVRhZ0Rpc3AsIGRlc2lnbikNCmNvbG5hbWVzKGNvZWYoZml0KSkgIA0KbHJ0IDwtIGdsbUxSVChmaXQsIGNvZWYgPSAyKSAgDQp0dEdsbSA8LSB0b3BUYWdzKGxydCwgbiA9IEluZikgIA0Kc3VtbWFyeShkZUdsbSA8LSBkZWNpZGVUZXN0c0RHRShscnQsIHAgPSAwLjA1LCBhZGp1c3QgPSAiZmRyIikpDQp0YWdzR2xtIDwtIHJvd25hbWVzKGRnZUdsbVRhZ0Rpc3ApW2FzLmxvZ2ljYWwoZGVHbG0pXQ0KcGxvdFNtZWFyKGxydCwgZGUudGFncyA9IHRhZ3NHbG0pDQpgYGANCg0KPGJyPg0KUk5BU2VxIGRhdGFzZXRzIG9mdGVuIGNvbnRhaW4gdGhvdXNhbmRzIG9mIGdlbmVzIGFjcm9zcyBtdWx0aXBsZSBzYW1wbGVzLCBtYWtpbmcgaXQgZXh0cmVtZWx5IGNvbXBsZXggdG8gZGV0ZWN0IGFuZCBhbmFseXplIHBhdHRlcm5zIG9mIGdlbmUgZXhwcmVzc2lvbiBkYXRhLiBJbiB0aGlzIGNvbnRleHQsICoqUHJpbmNpcGFsIENvbXBvbmVudCBBbmFseXNpcyoqICgqKlBDQSoqKSB0cmFuc2Zvcm1zIGRhdGEgaW50byBhIHNldCBvZiB1bmNvcnJlbGF0ZWQgdmFyaWFibGVzIChpLmUuLCBwcmluY2lwYWwgY29tcG9uZW50cyksIHdoaWNoIGlzIHVzZWZ1bCBmb3IgcmVkdWNpbmcgZGF0YSBkaW1lbnNpb25hbGl0eSwgcHJvdmlkaW5nIGEgKipibGluZCoqIGFuZCAqKnVuYmlhc2VkIGFzc2Vzc21lbnQqKiBvZiBnZW5lIGV4cHJlc3Npb24gcGF0dGVybnMgYWNyb3NzIG11bHRpcGxlIHNhbXBsZXMgYW5kIGNvbmRpdGlvbnMuIFBDMSBkZXNjcmliZXMgdGhlIG1vc3QgdmFyaWF0aW9uIHdpdGhpbiB0aGUgZGF0YSwgUEMyIHRoZSBzZWNvbmQgbW9zdCwgYW5kIHNvIGZvcnRoLg0KDQpUaGVyZWZvcmUsICoqUENBKiogaXMgaGlnaGx5IHZhbHVhYmxlIGZvciAqKihpKSoqIGlkZW50aWZ5aW5nICoqZ2VuZSBleHByZXNzaW9uIHRyZW5kcyoqIChlLmcuLCBjb25maXJtaW5nIHRoZSBiaW9sb2dpY2FsIHJlbGV2YW5jZSBvZiB0aGUgdHJlYXRtZW50L2Rpc2Vhc2Ugb3IgZXhwZXJpbWVudGFsIGNvbmRpdGlvbiksICoqKGlpKSoqIGlkZW50aWZ5aW5nICoqY2x1c3RlcnMqKiBvZiBzYW1wbGVzIGFuZCB0aGVpciByZWxhdGlvbnNoaXBzLCBhbmQgKiooaWlpKSoqIHNjcmVlbmluZyBvdXQgYW55IHBvdGVudGlhbCAqKm91dGxpZXJzKiogb3IgKipiYXRjaCBlZmZlY3RzKiouIFZpc3VhbGl6aW5nIHRoZXNlIGVmZmVjdHMgYXNzaXN0cyBpbiBjb25maXJtaW5nIHRoZSBoeXBvdGhlc2lzIHRlc3RlZCBpbiBmdXJ0aGVyICoqREVHcyoqIGRvd25zdHJlYW0gYW5hbHlzaXMuDQoNCg0KVG8gY3JlYXRlIGEgKipQQ0EgcGxvdCoqLCBmaXJzdCBhICoqdnN0KCkqKiAoKmkuZS4sIHZhcmlhbmNlLXN0YWJpbGl6aW5nIHRyYW5zZm9ybWF0aW9uKikgZnVuY3Rpb24gc2hvdWxkIGJlIGFwcGxpZWQgdG8gcmVtb3ZlIHRoZSBkZXBlbmRlbmNlIG9mIHRoZSB2YXJpYW5jZSBvbiB0aGUgbWVhbi4gVGhpcyBpcyBiZWNhdXNlIGFuYWx5c2lzIG9mIG11bHRpLWRpbWVuc2lvbmFsIGRhdGEgKHN1Y2ggYXMgUENBKSB3b3JrcyBiZXN0IGZvciBob21vc2tlZGFzdGljIGRhdGEgKGkuZS4sIGNvbnNpc3RlbnQgdmFyaWFiaWxpdHkpLCB3aGVyZWFzIGluIFJOQVNlcSBkYXRhIHZhcmlhbmNlIGluY3JlYXNlcyB3aXRoIHRoZSBtZWFuIHZhbHVlcy4gVW5saWtlIHRoZSBvdGhlciBERVNlcTIgZnVuY3Rpb24gKGkuZS4sICpybG9nKCkqKSBmdW5jdGlvbiBmb3IgdGhpcyBwdXJwb3NlLCAqKnZzdCgpKiogaXMgbW9yZSBzZW5zaXRpdmUgdG8gc2l6ZSBmYWN0b3IgYW5kIGFsc28gbm9ybWFsaXplcyB3aXRoIHJlc3BlY3QgdG8gbGlicmFyeSBzaXplLg0KDQoNCmBgYHtyIDJEIFBDQX0NCiNPdXRwdXQgMkQgUENBIFBsb3QNCnZzZGF0YSA8LSB2c3QoZGRzQ1BNLCBibGluZCA9IEZBTFNFKSAjQXBwbHkgdmFyaWFuY2Utc3RhYmlsaXppbmcgdHJhbnNmb3JtYXRpb24gdG8gREVTZXEgb2JqZWN0ICdkZHNDUE0nDQojQnkgZGVmYXVsdCBib3RoIHRoZXNlIGZ1bmN0aW9ucyBhcmUgKipibGluZCoqIHRvIHRoZSBzYW1wbGUgZGVzaWduIGZvcm11bGEgZ2l2ZW4gdG8gREVTZXEyIGluIERFU2VxRGF0YVNldEZyb21NYXRyaXgoKSwgaG93ZXZlciB0aGlzIGlzIG5vdCBhcHByb3ByaWF0ZSBpZiBvbmUgZXhwZWN0cyBsYXJnZSBkaWZmZXJlbmNlcyBpbiBjb3VudHMgZXhwbGFpbmVkIGJ5IGRpZmZlcmVuY2VzIGluIGV4cGVyaW1lbnRhbCBkZXNpZ24uIEluIHN1Y2ggY2FzZXMsIHRoZSBibGluZCBwYXJhbWV0ZXIgc2hvdWxkIGJlIHNldCB0byAnRkFMU0UnIGFzIHJlY29tbWVuZGVkIGluIERFU2VxMiB2aWduZXR0ZS4gDQoNCg0KI3Bsb3RQQ0EodnNkYXRhLCBpbnRncm91cCA9ICJ0cmVhdG1lbnQiKSAgICAgICAgICAjUHJldmlldyBQQzEgYW5kIFBDMiAlIGZvciBjb3JyZWN0IGF4aXMgbGFiZWxpbmcuDQpQQ0FyYXcgPC0gcGxvdFBDQSh2c2RhdGEsIGludGdyb3VwID0gInRyZWF0bWVudCIpICNDcmVhdGUgYSBQQ0EgcGxvdCB1c2luZyAndnNkYXRhJyBhbmQgZ3JvdXBzIGl0IGJ5ICd0cmVhdG1lbnQnLg0KZ3JvdXAuY29sb3JzIDwtIGMoIiM2MTlDRkYiLCIjMDBDMTlGIikgICAgICAgICAgICAjVmVjdG9yIGNvbnRhaW5pbmcgY29sb3IgY29kZXMgdG8gYmUgdXNlZCBpbiBlYWNoIGdyb3VwLg0KbmV3X3BjYSA8LSBnZ3Bsb3QoUENBcmF3W1siZGF0YSJdXSwgICAgICAgICAgICAgICAjQ3JlYXRlIGEgZ2dwbG90IHVzaW5nICdkYXRhJyBkYXRhLmZyYW1lIHdpdGhpbiAnUENBcmF3JyBvYmplY3QuIA0KICBhZXMoUEMxLCBQQzIsIGNvbG9yPWdyb3VwKSkgKyAgICAgICAgICAgICAgICAgICAjQ29uc3RydWN0IGFlc3RoZXRpYyBtYXBwaW5nIHVzaW5nIFBDMSBhbmQgUEMyLg0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gZ3JvdXAuY29sb3JzKSArICAgICAjU3BlY2lmeSBhIHZlY3RvciBvZiBjb2xvcnMuDQogIGdlb21fcG9pbnQoc2l6ZSA9IDIuNSkgKyAgICAgICAgICAgICAgICAgICAgICAgICNDaGFuZ2UgbWFya2VyIHNpemUuDQogIHhsYWIoIlBDMSAoNzklKSIpICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNUZXh0IHVzZWQgZm9yIFggYXhpcy4NCiAgeWxhYigiUEMyICg5JSkiKSArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI1RleHQgdXNlZCBmb3IgWSBheGlzLg0KICB5bGltKC0xMCwgMTApICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjTG93ZXIvdXBwZXIgbGltaXRzIGZvciBZIGF4aXMuDQogIHhsaW0oLTEyLCAxMikgKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNMb3dlci91cHBlciBsaW1pdHMgZm9yIFggYXhpcy4NCiAgdGhlbWVfZ3JleSgpICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI1NldCBhIGdyZXkgYmFja2dyb3VuZCB3aXRoIHdoaXRlIGdyaWRsaW5lcy4NCnRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpLCAgICAgI0N1c3RvbWl6ZSBzaXplIGFuZCBzdHlsZSBvZiBheGlzIHRpdGxlcyBhbmQgdGV4dC4NCiAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksDQogIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksDQogIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIikpDQoNCm5ld19wY2ENCmdnc2F2ZSgiMkRfUENBLnN2ZyIsIG5ld19wY2EsIGRwaSA9IDYwMCwgd2lkdGggPSAyLjYsIGhlaWdodCA9IDIsIHVuaXRzID0gImluIiwgc2NhbGUgPSAyKSAjRXhwb3J0cyBwbG90IGluIC5zdmcNCmBgYA0KPGJyPg0KQXBhcnQgZnJvbSAqKlBDQSoqLCBhbm90aGVyIGltcG9ydGFudCBhbmFseXNpcyB0byBwZXJmb3JtIGlzIHRvIGRldGVybWluZSB3aGV0aGVyICoqaW50ZXJncm91cCB2YXJpYWJpbGl0eSoqIC0gd2hpY2ggcmVwcmVzZW50cyBkaWZmZXJlbmNlcyBiZXR3ZWVuIGV4cGVyaW1lbnRhbCBjb25kaXRpb25zIGluIGNvbXBhcmlzb24gd2l0aCBjb250cm9sIGNvbmRpdGlvbnMgLSBpcyBncmVhdGVyIHRoYW4gdGhlICoqaW50cmFncm91cCB2YXJpYWJpbGl0eSoqLCByZXByZXNlbnRpbmcgdGVjaG5pY2FsIG9yIGJpb2xvZ2ljYWwgdmFyaWFuY2UuIFRoaXMgaXMgYWNoaWV2ZWQgYnkgKipjYWxjdWxhdGluZyBkaXN0YW5jZSoqIGFzIHJlcHJlc2VudGVkIGJ5IGNvcnJlbGF0aW9uIGFjcm9zcyBzYW1wbGVzLCB0eXBpY2FsbHkgdXNpbmcgdGhlICoqUGVhcnNvbidzIGNvcnJlbGF0aW9uIHBsb3QqKi4gDQoNCioqUGVhcnNvbidzKiogY29lZmZpY2llbnQgcmVmbGVjdHMgdGhlIGxpbmVhciByZWxhdGlvbnNoaXAgYmV0d2VlbiAyIHZhcmlhYmxlcyBhY2NvdW50aW5nIGZvciBkaWZmZXJlbmNlcyBpbiBtZWFuIGFuZCBzdGFuZGFyZCBkZXZpYXRpb24uIEZvciBpbnN0YW5jZSwgdGhlICoqbW9yZSBzaW1pbGFyIHRoZSBnZW5lIGV4cHJlc3Npb24gcHJvZmlsZXMgZm9yIGFsbCB0cmFuc2NyaXB0cyoqIGFyZSBiZXR3ZWVuIHR3byBzYW1wbGVzLCB0aGUgKipoaWdoZXIgdGhlIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50Kiogd2lsbCBiZS4gVGhlc2UgY29lZmZpY2llbnRzIGFyZSBjYWxjdWxhdGVkIGJldHdlZW4gYWxsIHNhbXBsZXMgYW5kIGFyZSB0aGVuICoqdmlzdWFsaXplZCBhcyBhIGhlYXRtYXAqKi4NCg0KU2ltaWxhciB0byBQQ0EsIHRoZSAqKlBlYXJzb24ncyBjb3JyZWxhdGlvbiBwbG90KiogcHJvdmlkZXMgYW4gb3ZlcnZpZXcgb2YgdGhlICoqb3ZlcmFsbCBzdHJlbmd0aCBvZiB0aGUgYmlvbG9naWNhbCBlZmZlY3QqKiBvZiB0aGUgZXhwZXJpbWVudCwgYXNzZXNzaW5nIHdoZXRoZXIgcmVwbGljYXRlcyBhbmQgZGlmZmVyZW50IGNvbmRpdGlvbnMgZ3JvdXAgdG9nZXRoZXIsIGFzIHdlbGwgYXMgaWRlbnRpZnkgb3V0bGllcnMgdGhhdCB3ZXJlIG5vdCBleGNsdWRlZCBkdXJpbmcgdXBzdHJlYW0gc3RlcHMgKGUuZy4sIHNhbXBsZSBsYWJlbGluZyBvciBnZW5vbWljIGFsaWdubWVudCkuDQoNCg0KDQpgYGB7ciAyRCBTYW1wbGUgRGlzdGFuY2VzIENvcnJlbGF0aW9ufQ0KI091dHB1dCAyRCBQZWFyc29uJ3MgQ29ycmVsYXRpb24gUGxvdA0KdnNkYXRhIDwtIHZzdChkZHNDUE0sIGJsaW5kID0gRkFMU0UpICAgICAgICAgICAgICAgICAgICAjQXBwbHkgdmFyaWFuY2Utc3RhYmlsaXppbmcgdHJhbnNmb3JtYXRpb24uDQpzYW1wbGVEaXN0cyA8LSBjb3IobWV0aG9kID0gInBlYXJzb24iLCBhc3NheSh2c2RhdGEpKSAgICNDYWxjdWxhdGUgUGVhcnNvbiBjb3JyZWxhdGlvbiBjb2VmZmljaWVudHMuDQpzYW1wbGVEaXN0TWF0cml4IDwtIGFzLm1hdHJpeChzYW1wbGVEaXN0cykgICAgICAgICAgICAgICNDb252ZXJ0IHRvIG1hdHJpeCBmb3JtYXQuDQpyb3duYW1lcyhzYW1wbGVEaXN0TWF0cml4KSA8LSBwYXN0ZSh2c2RhdGEkaWQpICAgICAgICAgICNMYWJlbCBTYW1wbGUgbmFtZXMuDQpjb2xuYW1lcyhzYW1wbGVEaXN0TWF0cml4KSA8LSBwYXN0ZSh2c2RhdGEkaWQpICAgICAgICAgICNMYWJlbCBTYW1wbGUgbmFtZXMuDQpjb2xvcnMgPC0gY29sb3JSYW1wUGFsZXR0ZShicmV3ZXIucGFsKDksICJCbHVlcyIpKSgyNTUpICNDb2xvciBwYWxldHRlIHJhbmdlIGZvciBoZWF0bWFwIHZpc3VhbGl6YXRpb24uDQpTYW1wbGVEaXN0YW5jZSA9IHBoZWF0bWFwKHNhbXBsZURpc3RNYXRyaXgsIGNvbD1jb2xvcnMpICNHZW5lcmF0ZSBoZWF0bWFwIHdpdGggJ3NhbXBsZURpc3RNYXRyaXgnIGFuZCAnY29sb3JzJyBpbnB1dHMuDQpTYW1wbGVEaXN0YW5jZSAjZ2dzYXZlKCJTRF8yRF9QZWFyc29uLnN2ZyIsIFNhbXBsZURpc3RhbmNlLCBkcGkgPSA2MDAsIHdpZHRoID0gMi41NSwgaGVpZ2h0ID0gMiwgdW5pdHMgPSAiaW4iLCBzY2FsZSA9IDIpIA0KYGBgDQoNCmBgYHtyIEV1Y2xpZGVhbiBEaXN0YW5jZXMgQ29ycmVsYXRpb24gREVTZXEyIHZpZ25ldHRlfQ0KI0FsdGVybmF0aXZlOiBFdWNsaWRlYW4gRGlzdGFuY2VzIENvcnJlbGF0aW9uIFBsb3QsIGFzIGRlc2NyaWJlZCBpbiBERVNlcTIgdmlnbmV0dGUNCnNhbXBsZURpc3RzX0V1Y2xpZGVhbiA8LSBkaXN0KHQoYXNzYXkodnNkYXRhKSkpICAgICAgICAgICAgICAgICAjQ2FsY3VsYXRlIFBlYXJzb24gY29ycmVsYXRpb24gY29lZmZpY2llbnRzLg0Kc2FtcGxlRGlzdE1hdHJpeF9FdWNsaWRlYW4gPC0gYXMubWF0cml4KHNhbXBsZURpc3RzX0V1Y2xpZGVhbikgICNDb252ZXJ0IHRvIG1hdHJpeCBmb3JtYXQuDQpyb3duYW1lcyhzYW1wbGVEaXN0TWF0cml4X0V1Y2xpZGVhbikgPC0gcGFzdGUodnNkYXRhJGlkKSAgICAgICAgI0xhYmVsIFNhbXBsZSBuYW1lcy4NCmNvbG5hbWVzKHNhbXBsZURpc3RNYXRyaXhfRXVjbGlkZWFuKSA8LSBwYXN0ZSh2c2RhdGEkaWQpICAgICAgICAjTGFiZWwgU2FtcGxlIG5hbWVzLg0KY29sb3JzIDwtIGNvbG9yUmFtcFBhbGV0dGUocmV2KGJyZXdlci5wYWwoOSwgIkJsdWVzIikpKSgyNTUpICAgICNDb2xvciBwYWxldHRlIHJhbmdlIGZvciBoZWF0bWFwIHZpc3VhbGl6YXRpb24uDQpTYW1wbGVEaXN0YW5jZXZpZ25ldHRlID0gcGhlYXRtYXAoc2FtcGxlRGlzdE1hdHJpeF9FdWNsaWRlYW4sICAgI0dlbmVyYXRlIGhlYXRtYXAgd2l0aCAnc2FtcGxlRGlzdE1hdHJpeCcgYW5kICdjb2xvcnMnIGlucHV0cy4NCiAgICAgICAgIGNsdXN0ZXJpbmdfZGlzdGFuY2Vfcm93cz1zYW1wbGVEaXN0c19FdWNsaWRlYW4sICAgICAgICAjQ2x1c3RlcmluZyBieSBFdWNsaWRlYW4gZGlzdGFuY2UuDQogICAgICAgICBjbHVzdGVyaW5nX2Rpc3RhbmNlX2NvbHM9c2FtcGxlRGlzdHNfRXVjbGlkZWFuLCAgICAgICAgI0NsdXN0ZXJpbmcgYnkgRXVjbGlkZWFuIGRpc3RhbmNlLg0KICAgICAgICAgY29sPWNvbG9ycykNClNhbXBsZURpc3RhbmNldmlnbmV0dGUgI2dnc2F2ZSgiMkRfU0Quc3ZnIiwgU2FtcGxlRGlzdGFuY2V2aWduZXR0ZSwgZHBpID0gNjAwLCB3aWR0aCA9IDIuNTUsIGhlaWdodCA9IDIsIHVuaXRzID0gImluIiwgc2NhbGUgPSAyKQ0KYGBgDQo8YnI+DQo8YnI+DQpOZXh0LCBhICoqVm9sY2FubyBwbG90KiogY2FuIGJlIGFzc2VtYmxlZCB0byBwcm92aWRlIGEgZ2VuZXJhbCBvdmVydmlldyBvZiB0aGUgZ2VuZSBleHByZXNzaW9uIHByb2ZpbGVzIG9mIDJEIE5hdGl2ZSBoQVNDcyB2cyAyRCBHbHljb2VuZ2luZWVyZWQgaEFTQ3MuICoqVm9sY2FubyBwbG90cyoqIHByb3ZpZGUgYSBjbGVhciBhbmQgaW50dWl0aXZlIHZpc3VhbGl6YXRpb24gb2YgKipzdGF0aXN0aWNhbCBzaWduaWZpY2FuY2UqKiBhbmQgdGhlICoqZXh0ZW50IG9mIGZvbGQgY2hhbmdlcyoqIGZvciBldmVyeSBnZW5lIGRldGVjdGVkLiBIZXJlLCBlYWNoIGdlbmUgaXMgcGxvdHRlZCB3aXRoIHRoZWlyIHN0YXRpc3RpY2FsIHNpZ25pZmljYW5jZSAoYWRqdXN0ZWQgcC12YWx1ZXMgb24gdGhlIHktYXhpcykgYWdhaXNudCB0aGUgZm9sZCBjaGFuZ2UgKGxvZzIgZm9sZCBjaGFuZ2Ugb24gdGhlIHgtYXhpcykuIA0KDQpUaGVuLCBhICoqdGhyZXNob2xkKiogaXMgc2V0IHRvIGhpZ2hsaWdodCBnZW5lcyB0aGF0IGFyZSBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgKCoqREVHcyoqKSwgYXMgcmVwcmVzZW50ZWQgaW4gdGhlIHBsb3QgaW4gdGhlIGZvcm0gb2YgZGFzaGVkIGxpbmVzLiBBcyBhZm9yZW1lbnRpb25lZCwgdGhpcyB3b3JrIGNvbnNpZGVycyBhcyAqKkRFR3MqKiBnZW5lcyB0aGF0IHByZXNlbnQgYW4gKiphZGp1c3RlZCBwLXZhbHVlIDwgMC4wNSoqIGFuZCAqKmxvZzIoZm9sZCBjaGFuZ2UpID4gMSoqIG9yICoqPCAtMSoqLiBUaGlzICoqY29tYmluYXRpb24gb2Ygc2lnbmlmaWNhbmNlIGFuZCBmb2xkIGNoYW5nZSoqIGluZm9ybWF0aW9uIGFsbG93cyByZXNlYXJjaGVycyB0byBlZmZpY2llbnRseSAqKmlkZW50aWZ5KiogYW5kICoqcHJpb3JpdGl6ZSoqICoqZ2VuZXMgb2YgaW50ZXJlc3QqKiBmb3IgZnVydGhlciBpbnZlc3RpZ2F0aW9uLiBJbiBhZGRpdGlvbiwgKipWb2xjYW5vIHBsb3RzKiogY2FuIGFsc28gYXNzaXN0IGluIHNjcmVlbmluZyBvdXQgZ2VuZXMgd2l0aCBoaWdoIHN0YXRpc3RpY2FsIHNpZ25pZmljYW5jZSBidXQgbG93IGZvbGQgY2hhbmdlcywgd2hpY2ggbWF5IGJlIHNpZ25pZmljYW50IGR1ZSB0byBsYXJnZSBzYW1wbGUgc2l6ZXMgYnV0IG1heSBub3QgaGF2ZSBzdWJzdGFudGlhbCBiaW9sb2dpY2FsIHJlbGV2YW5jZS4NCg0KYGBge3IgMkQgVm9sY2FubyBwbG90LCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0KI091dHB1dCAyRCBWb2xjYW5vIHBsb3Qgd2l0aCBzcGVjaWZpYyBHZW5lcyBvZiBJbnRlcmVzdCBsYWJlbGxlZA0KDQpyZXNkZHNDUE0uZGYgPC0gYXMuZGF0YS5mcmFtZShyZXNkZHNDUE0pICAgICAgICAgICAgICAgICAgICAgICAgI0NvbnZlcnQgREVTZXEyIHJlc3VsdHMgb2JqZWN0IHRvIGEgZGF0YSBmcmFtZS4NCg0KI0NyZWF0ZSBjdXN0b20ga2V5LXZhbHVlIHBhaXJzIGZvciAnVXAnLCAnRG93bicsICdOb24tREVHJyBleHByZXNzaW9uLiBBY2hpZXZlZCB1c2luZyBuZXN0ZWQgJ2lmZWxzZScgc3RhdGVtZW50cy4NCmtleXZhbHMgPC0gIGlmZWxzZShyZXNkZHNDUE0kcGFkaiA+IDAuMDUsICdncmV5MzAnLCAgICAgICAgICAgICAjSWYgcGFkaiA+IDAuMDUgYXNzaWduIGdyZXkgY29sb3IuDQogICAgICAgICAgICBpZmVsc2UocmVzZGRzQ1BNJGxvZzJGb2xkQ2hhbmdlIDwgLTEsICdyb3lhbGJsdWUnLCAgI0lmIGxvZzJmb2xkY2hhbmdlIDwgLTEsIGFzc2lnbiBibHVlIGNvbG9yLg0KICAgICAgICAgICAgaWZlbHNlKHJlc2Rkc0NQTSRsb2cyRm9sZENoYW5nZSA+IDEsICdmaXJlYnJpY2szJywgICNJZiBsb2cyZm9sZGNoYW5nZSA+IDEsIGFzc2lnbiByZWQgY29sb3IuDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdncmV5MzAnKSkpICAgI090aGVyIHZhbHVlcyBhc3NpZ25lZCBncmV5IGNvbG9yLg0KI1JlbmFtZSBlbGVtZW50cyBpbiAna2V5dmFscycgdmVjdG9yOg0KbmFtZXMoa2V5dmFscylba2V5dmFscyA9PSAnZmlyZWJyaWNrMyddIDwtICdVcCcgICAgICAgICAgICAgICAgICNBc3NpZ24gJ1VwJyB0byBlbGVtZW50cyBpbiByZWQuDQpuYW1lcyhrZXl2YWxzKVtrZXl2YWxzID09ICdncmV5MzAnXSA8LSAnTm9uLURFRycgICAgICAgICAgICAgICAgI0Fzc2lnbiAnTm9uLURFRycgdG8gZWxlbWVudHMgaW4gcmVkLg0KbmFtZXMoa2V5dmFscylba2V5dmFscyA9PSAncm95YWxibHVlJ10gPC0gJ0Rvd24nICAgICAgICAgICAgICAgICNBc3NpZ24gJ1VwJyB0byBlbGVtZW50cyBpbiByZWQuDQoNCiNEZWZpbmUgdmVjdG9yIGNvbnRhaW5pbmcgR2VuZSBTeW1ib2xzIHRvIGhpZ2hsaWdodCBpbiBwbG90DQpzZWxlY3RlZCA9IGMoIlBUR1MyIiwgIktSVDE5IiwgIkNYQ0wxIiwgIlNMQzdBMTEiLCAiTkRORiIsICJQR0QiLCAiVkNBTTEiLCAiR1BDMSIsICJBTkdQVDEiLCAiR0RGMTUiKQ0KDQojVm9sY2FubyBwbG90IHNldHRpbmdzDQplbmh2b2xjIDwtIEVuaGFuY2VkVm9sY2FubyhyZXNkZHNDUE0uZGYsICAgICAgICAgICAgICAgICAgICAgICAgI0NyZWF0ZSBWb2xjYW5vIHBsb3QgdXNpbmcgJ3Jlc2Rkc0NQTS5kZicNCiAgICAgICAgeCA9ICJsb2cyRm9sZENoYW5nZSIsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjQ29sdW1uIG5hbWUgY29udGFpbmluZyBsb2cyKGZvbGQgY2hhbmdlKSB2YWx1ZXMuDQogICAgICAgIHkgPSAicGFkaiIsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI0NvbHVtbiBuYW1lIGNvbnRhaW5pbmcgYWRqdXN0ZWQgcC12YWx1ZSB2YWx1ZXMuDQogICAgICAgICNsYWIgPSBOQSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI1VuY29tbWVudCB0aGlzIGZ1bmN0aW9uIGZvciB1bmxhYmVsZWQgZ2VuZXMuDQogICAgICAgIHBDdXRvZmYgPSAwLjA1LCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI0N1dC1vZmYgdGhyZXNob2xkIGZvciBzdGF0aXN0aWNhbCBzaWduaWZpY2FuY2UuDQogICAgICAgIEZDY3V0b2ZmID0gMSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI0N1dC1vZmYgdGhyZXNob2xkIGZvciBhYnNvbHV0ZSBsb2cyKGZvbGQgY2hhbmdlKS4NCiAgICAgICAgdGl0bGUgPSBOVUxMLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjUGxvdCB0aXRsZS4NCiAgICAgICAgc3VidGl0bGUgPSBOVUxMLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjUGxvdCBzdWJ0aXRsZS4NCiAgICAgICAgY2FwdGlvbiA9IE5VTEwsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjUGxvdCBjYXB0aW9uLg0KICAgICAgICB4bGFiID0gYnF1b3RlKH5Mb2dbMl1+IihGb2xkIENoYW5nZSkiKSwgICAgICAgICAgICAgICAgICNMYWJlbCBmb3IgeC1heGlzLiANCiAgICAgICAgeWxhYiA9IGJxdW90ZSh+LUxvZ1sxMF0gfiAiKCIgKiBpdGFsaWMoUFthZGpdKSAqICIpIiksICAjTGFiZWwgZm9yIHktYXhpcy4NCiAgICAgICAgY29sQWxwaGEgPSAwLjUsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjQWxwaGEgZm9yIGNvbG9yIHRyYW5zcGFyZW5jeS4NCiAgICAgICAgY29sQ3VzdG9tID0ga2V5dmFscywgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjT3ZlcnJpZGUgY29sb3Igc2NoZW1lIChlLmcuIGNvbG9yIGJ5IHBhdGh3YXksIGNlbGwtdHlwZSBvciBjb25kaXRpb24pLg0KICAgICAgICBwb2ludFNpemUgPSAxLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNTaXplIG9mIHBsb3R0ZWQgcG9pbnRzLg0KICAgICAgICBsYWJTaXplID0gNCwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNTaXplIG9mIGxhYmVscyBmb3IgZWFjaCBwb2ludC4NCiAgICAgICAgZHJhd0Nvbm5lY3RvcnMgPSBUUlVFLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjQ29ubmVjdCBsYWJlbHMgdG8gZWFjaCBjb3JyZXNwb25kaW5nIHBvaW50IGJ5IGxpbmUgY29ubmVjdG9ycy4NCiAgICAgICAgd2lkdGhDb25uZWN0b3JzID0gMC42NSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjTGluZSB3aWR0aCBvZiBjb25uZWN0b3JzLg0KICAgICAgICBhcnJvd2hlYWRzID0gRkFMU0UsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNEcmF3IGFycm93aGVhZHMgaW5zdGVhZCBvZiBzaW1wbGUgbGluZSBjb25uZWN0b3JzLg0KICAgICAgICBib3hlZExhYmVscyA9IFRSVUUsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNEcmF3IGxhYmVscyB3aXRoaW4gYm94ZXMuDQogICAgICAgIGRpcmVjdGlvbkNvbm5lY3RvcnMgPSAnYm90aCcsICAgICAgICAgICAgICAgICAgICAgICAgICAgI0RpcmVjdGlvbiB0byBkcmF3IGNvbm5lY3RvcnMgKGUuZy4sICd5JywgJ3gnIG9yICdib3RoJykuDQogICAgICAgIHhsaW0gPSBjKC02LCA2KSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI0xpbWl0cyBvZiB4LWF4aXMuDQogICAgICAgIHlsaW0gPSBjKDAsIC1sb2cxMCgxMGUtMjU1KSksICAgICAgICAgICAgICAgICAgICAgICAgICAgI0xpbWl0cyBvZiB5LWF4aXMuDQojRXhjbHVkZSB0aGVzZSBpZiBub3QgaGlnaGxpZ2h0aW5nIHNwZWNpZmljIGdlbmVzDQogICAgICAgIGxhYiA9IHJlc2Rkc0NQTS5kZiRnZW5lSUQsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI0lucHV0IEdlbmUgU3ltYm9sIGNvbHVtbiBvZiBkYXRhLmZyYW1lIG9iamVjdC4NCiAgICAgICAgc2VsZWN0TGFiID0gc2VsZWN0ZWQgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjVmVjdG9yIGNvbnRhaW5pbmcgYSBzdWJzZXQgb2YgZ2VuZXMgb2YgaW50ZXJlc3QuDQogICAgICAgICkNCg0KI0N1c3RvbWl6ZSBheGlzIGxpbWl0cyBhbmQgYnJlYWtzDQpwMSA8LSAgZW5odm9sYyArDQogICAgZ2dwbG90Mjo6Y29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKC02LjQsIDYuNCksICAgICAgICAgICAgICAgI1pvb20gcGxvdCB0byB0aGUgc3BlY2lmaWMgeC1heGlzIGxpbWl0LiANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWxpbSA9IGMoMCwgMjUwKSkgKyAgICAgICAgICAgICAgICAjWm9vbSBwbG90IHRvIHRoZSBzcGVjaWZpYyB5LWF4aXMgbGltaXQuIA0KICAgIGdncGxvdDI6OnNjYWxlX3hfY29udGludW91cyhicmVha3M9c2VxKC02LCA2LCAyKSkgKyAgICAgICAgICNTZXQgc3BhY2luZyBvZiBicmVha3MgaW4gcGxvdCB4LWF4aXMuDQogICAgZ2dwbG90Mjo6c2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1zZXEoMCwgMjUwLCA1MCkpICAgICAgICAgI1NldCBzcGFjaW5nIG9mIGJyZWFrcyBpbiBwbG90IHktYXhpcy4NCnAxDQpnZ3NhdmUoIjJEX1ZvbGNhbm9fV2lkZV9MYWJlbC5zdmciLCBwMSwgd2lkdGggPSA0LjUsIGhlaWdodCA9IDIuOCwgdW5pdHMgPSAiaW4iLCBzY2FsZSA9IDIpDQpgYGANCjxicj4NCkFsdGVybmF0aXZlbHksICoqVm9sY2FubyBwbG90cyoqIGNhbiBiZSBjdXN0b21pemVkIHZpYSBvdGhlciBwYWNrYWdlcyAoZS5nLiwgKidnZ3Bsb3QyJyopIGFzIHN1YnBsb3Qgb3ZlcmxheXMgZm9yIHByZXNlbnRpbmcgYSBsaXN0IG9mIHRhcmdldCBnZW5lcyB3aXRoIGRpZmZlcmVudCBzaGFkaW5nIHNwZWNpZmljYXRpb25zLg0KDQpGb3IgaW5zdGFuY2UsICoqb3ZlcmxheWluZyoqIGFsbCBnZW5lcyB0aGF0ICoqbWF0Y2ggYSBzcGVjaWZpYyByZXF1aXJlbWVudCoqIChpLmUuLCBhbGwgSUxzIGdlbmVzKS4NCg0KYGBge3IgZ2dwbG90MiBWb2xjYW5vLCBpbmNsdWRlPUZBTFNFLCBlY2hvPUZBTFNFfQ0KI0FsdGVybmF0aXZlIFZvbGNhbm8gcGxvdCBmbGV4aWJpbGl0eSB0aHJvdWdoICdnZ3Bsb3QyJyBwYWNrYWdlLiBOb3RlOiBkb2Vzbid0IGhhdmUgRW5oYW5jZWRWb2xjYW5vIGZsZXhpYmlsaXR5IGZvciBjb3JyZWN0aW5nIHAtdmFsdWVzID0gMC4NCg0KcmVzZGRzQ1BNVk9MQy5kZiA8LSByZXNkZHNDUE0uZGYNCiNBZGQgYSBjb2x1bW4gdG8gdGhlIGRhdGEgZnJhbWUgdG8gc3BlY2lmeSBpZiBnZW5lcyBhcmUgVVAtIG9yIERPV04tIHJlZ3VsYXRlZCBERUdzDQpyZXNkZHNDUE1WT0xDLmRmJGRpZmZleHByZXNzZWQgPC0gIk5vbi1ERUciDQojVVBSRUdVTEFURUQgREVHcw0KcmVzZGRzQ1BNVk9MQy5kZiRkaWZmZXhwcmVzc2VkW3Jlc2Rkc0NQTVZPTEMuZGYkbG9nMkZvbGRDaGFuZ2UgPiAxICYgcmVzZGRzQ1BNVk9MQy5kZiRwYWRqIDwgMC4wNV0gPC0gIlVwcmVndWxhdGVkIg0KI0RPV05SRUdVTEFURUQgREVHcw0KcmVzZGRzQ1BNVk9MQy5kZiRkaWZmZXhwcmVzc2VkW3Jlc2Rkc0NQTVZPTEMuZGYkbG9nMkZvbGRDaGFuZ2UgPCAtMSAmIHJlc2Rkc0NQTVZPTEMuZGYkcGFkaiA8IDAuMDVdIDwtICJEb3ducmVndWxhdGVkIg0KDQojVm9sY2FubyAnZ2dwbG90MicgdGhlbWUNCnZvbGNfdGhlbWUgPC0gdGhlbWVfc2V0KHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplID0gMjApICsNCiAgICAgICAgICAgIHRoZW1lKA0KICAgICAgICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgbWFyZ2luID0gbWFyZ2luKDAsMTAsMCwwKSwgc2l6ZSA9IDE1LCBjb2xvciA9ICdibGFjaycpLA0KICAgICAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIsIG1hcmdpbiA9IG1hcmdpbigxMCwwLDAsMCksIHNpemUgPSAxNSwgY29sb3IgPSAnYmxhY2snKSwNCiAgICAgICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkNCiAgICAgICAgICAgICkpDQoNCmdncGxvdChkYXRhID0gcmVzZGRzQ1BNVk9MQy5kZiwNCiAgICAgICBhZXMoeCA9IGxvZzJGb2xkQ2hhbmdlLA0KICAgICAgICAgICB5ID0gLWxvZzEwKHBhZGopLA0KICAgICAgIGNvbCA9IGRpZmZleHByZXNzZWQpKSArDQogICAgICAgZ2VvbV9wb2ludChzaXplID0gMSkgKyANCiAgICAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjKC0xLCAxKSwgY29sID0gJ2dyZXkzMCcsIGxpbmV0eXBlID0gJ2Rhc2hlZCcpICsNCiAgICAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBjKC1sb2cxMCgwLjA1KSksIGNvbCA9ICdncmV5MzAnLCBsaW5ldHlwZSA9ICdkYXNoZWQnKSArDQogICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoInJveWFsYmx1ZSIsICJncmV5MzAiLCAiZmlyZWJyaWNrMyIpLCAjU2V0IGNvbG9yIHZlY3RvcnMgZm9yIGdlbmUgY2xhc3NpZmljYXRpb25zDQogICAgICAgICAgIGxhYmVscyA9IGMoIkRvd25yZWd1bGF0ZWQiLCAiTm9uLURFR3MiLCAiVXByZWd1bGF0ZWQiKSkgKyAjU2V0IGxhYmVsIG5hbWVzIHRvIG92ZXJ3cml0ZSB0ZXh0IGluIGRhdGEuZnJhbWUgKFVQLCBET1dOLCBOTykNCiAgICAgICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMCwgMzAwKSwgeGxpbSA9IGMoLTExLCAxMSkpICsgI1NldCBsaW1pdHMgZHVlIHRvIHBhZGogPSAwIG9uIHNvbWUgZ2VuZXMsIHRoZXkgd2lsbCBzdGlsbCBiZSBwbG90dGVkIGJ1dCBjb2xsYXBzZWQgb24gZWRnZQ0KICAgICAgIGxhYnMoY29sb3IgPSAnTGVnZW5kJywgI0xlZ2VuZCB0aXRsZSwgDQogICAgICAgICAgIHggPSBleHByZXNzaW9uKCJMb2ciWzJdKiIoRm9sZCBDaGFuZ2UpIiksDQogICAgICAgICAgIHkgPSBleHByZXNzaW9uKCItTG9nIlsxMF0qUFthZGpdKSkgKyANCiAgICAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IGMoc2VxKC0xMCwgMTAsIDUpKSwgI0N1c3RvbWl6ZSB4LWF4aXMgdGlja3MNCiAgICAgICAgICAgbGltaXRzID0gYygtMjAsIDIwKSkgKyAjU2hvdyBkYXRhcG9pbnRzIHdpdGhpbiB0aGlzIHJlZ2lvbg0Kdm9sY190aGVtZQ0KYGBgDQoNCmBgYHtyIGdncGxvdDIgVm9sY2FubyBzZXR0aW5ncywgaW5jbHVkZT1GQUxTRX0NCnJlc2Rkc0NQTVZPTEMuZGYgJT4lDQogIGRpc3RpbmN0KGRpZmZleHByZXNzZWQpICU+JQ0KICBwdWxsKCkgIA0KIyAiTk8iICAiVVAiICAiRE9XTiINCg0KY29scyA8LSBjKCJEb3ducmVndWxhdGVkIiA9ICJyb3lhbGJsdWUiLCAiVXByZWd1bGF0ZWQiID0gImZpcmVicmljazMiLCAiTm9uLURFRyIgPSAiZ3JleTMwIikgDQpzaXplcyA8LSBjKCJEb3ducmVndWxhdGVkIiA9IDEsICJVcHJlZ3VsYXRlZCIgPSAxLCAiTm9uLURFRyIgPSAxKSANCmFscGhhcyA8LSBjKCJEb3ducmVndWxhdGVkIiA9IDAuNSwgIlVwcmVndWxhdGVkIiA9IDAuNSwgIk5vbi1ERUciID0gMC41KQ0KIyAiI2ZmYWQ3MyIsICJkb3duIiA9ICIjMjZiM2ZmIg0KDQpnZ3Bsb3RWb2xjIDwtIGdncGxvdChkYXRhID0gcmVzZGRzQ1BNVk9MQy5kZiwgYWVzKHggPSBsb2cyRm9sZENoYW5nZSwgeSA9IC1sb2cxMChwYWRqKSwNCiAgZmlsbCA9IGRpZmZleHByZXNzZWQsDQogIHNpemUgPSBkaWZmZXhwcmVzc2VkLA0KICBhbHBoYSA9IGRpZmZleHByZXNzZWQpKSArDQogIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwNCiAgICAgICAgICAgICBjb2xvdXIgPSAiYmxhY2siKSArIA0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjKC0xLCAxKSwgY29sID0gJ2dyZXkzMCcsIGxpbmV0eXBlID0gJ2Rhc2hlZCcpICsNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gYygtbG9nMTAoMC4wNSkpLCBjb2wgPSAnZ3JleTMwJywgbGluZXR5cGUgPSAnZGFzaGVkJykgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2xzKSArICMgTW9kaWZ5IHBvaW50IGNvbG9yDQogIHNjYWxlX3NpemVfbWFudWFsKHZhbHVlcyA9IHNpemVzKSArICMgTW9kaWZ5IHBvaW50IHNpemUNCiAgc2NhbGVfYWxwaGFfbWFudWFsKHZhbHVlcyA9IGFscGhhcykgKyAjIE1vZGlmeSBwb2ludCB0cmFuc3BhcmVuY3kNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IGMoc2VxKC0xMCwgMTAsIDUpKSwgICAgICAgDQogICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKC0xMCwgMTApKSArDQogIGxhYnMoY29sb3IgPSAnTGVnZW5kJywgI2xlZ2VuZF90aXRsZSwgDQogICAgICAgeCA9IGV4cHJlc3Npb24oImxvZyJbMl0qIkZvbGQgQ2hhbmdlIiksIHkgPSBleHByZXNzaW9uKCItbG9nIlsxMF0qUFthZGpdKSkNCg0KZ2dwbG90Vm9sYw0KI2dnc2F2ZSgiMkR2czNEX2dncGxvdFZvbGMuc3ZnIiwgZ2dwbG90Vm9sYywgd2lkdGggPSAzLjgsIGhlaWdodCA9IDIuNSwgdW5pdHMgPSAiaW4iLCBzY2FsZSA9IDIpDQpgYGANCg0KYGBge3IgR0dQTE9UIFZvbGNhbm8gT3ZlcmxheSBhbmQgU3BlY2lmaWMgTGFiZWxpbmcgMiwgZWNobz1GQUxTRX0NCiMtLS0tLS0tLS0tLS0tLU9WRVJMQVkgVEFSR0VUIEdFTkVTIE9OIEdSRVlFRCBPVVQgVk9MQ0FOTyBQTE9UUy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIEFkZCBzdWJwbG90IGxheWVyIHRvIHRoZSBtYWluIHZvbGNhbm8gcGxvdCAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KaWxzIDwtIHN0cl9zdWJzZXQocmVzZGRzQ1BNVk9MQy5kZiRnZW5lSUQsICJeSUwiKSAjIl4oSXxMKXsyfVswLTldKyQiKSAgI1RoaXMgZmV0Y2hlcyBnZW5lIHN5bWJvbHMgc3RhcnRpbmcgd2l0aCBJTCBpbiB0aGUgbmFtZS4NCiNsZW5ndGgoaWxzKSAjNTINCg0KaWxfZ2VuZXMgPC0gcmVzZGRzQ1BNVk9MQy5kZiAlPiUNCiAgZmlsdGVyKGdlbmVJRCAlaW4lIGlscykNCg0KZ2dwbG90Vm9sY19zdWJsYXllciA8LSBnZ3Bsb3QoZGF0YSA9IHJlc2Rkc0NQTVZPTEMuZGYsICMgT3JpZ2luYWwgZGF0YSAgDQogICAgICAgYWVzKHggPSBsb2cyRm9sZENoYW5nZSwgeSA9IC1sb2cxMChwYWRqKSkpICsgDQogIGdlb21fcG9pbnQoY29sb3VyID0gImdyZXkiLCBhbHBoYSA9IDAuNSkgKw0KICBnZW9tX3BvaW50KGRhdGEgPSBpbF9nZW5lcywgIyBOZXcgbGF5ZXIgY29udGFpbmluZyBkYXRhIHN1YnNldCBpbF9nZW5lcyAgICAgICANCiAgICAgICAgICAgICBzaXplID0gMiwNCiAgICAgICAgICAgICBzaGFwZSA9IDIxLA0KICAgICAgICAgICAgIGZpbGwgPSAiZmlyZWJyaWNrIiwNCiAgICAgICAgICAgICBjb2xvdXIgPSAiYmxhY2siKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoLTEsIDEpLCBjb2wgPSAnZ3JleTMwJywgbGluZXR5cGUgPSAnZGFzaGVkJykgKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBjKC1sb2cxMCgwLjA1KSksIGNvbCA9ICdncmV5MzAnLCBsaW5ldHlwZSA9ICdkYXNoZWQnKSArDQogIGxhYnMoY29sb3IgPSAnTGVnZW5kJywgI2xlZ2VuZF90aXRsZSwgDQogICAgICAgeCA9IGV4cHJlc3Npb24oImxvZyJbMl0qIihGb2xkIENoYW5nZSkiKSwgeSA9IGV4cHJlc3Npb24oIi1sb2ciWzEwXSpQW2Fkal0pKSArIA0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gYyhzZXEoLTEwLCAxMCwgNSkpLCAjQ3VzdG9taXplIFggYXhpcyB0aWNrcw0KICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygtMTAsIDEwKSkgKyAjIFNob3cgZGF0YXBvaW50cyB3aXRoaW4gdGhpcyByZWdpb24NCiAgdm9sY190aGVtZQ0KDQpnZ3Bsb3RWb2xjX3N1YmxheWVyDQojZ2dzYXZlKCIyRF9nZ3Bsb3RWb2xjX3N1Yi5zdmciLCBnZ3Bsb3RWb2xjX3N1YmxheWVyLCB3aWR0aCA9IDMuOCwgaGVpZ2h0ID0gMywgdW5pdHMgPSAiaW4iLCBzY2FsZSA9IDIpDQpgYGANCjxicj4NCkluIGFkZGl0aW9uLCBpdCBpcyBhbHNvIHBvc3NpYmxlIHRvIGFzc2VtYmxlIGEgKipWb2xjYW5vIHBsb3QqKiBjb250YWluaW5nIGFuICoqb3ZlcmxheSoqIG9mIGdlbmVzIG9mIGludGVyZXN0IG9uIHRvcC4NCg0KIVtdKFRyZWF0ZWQvMkR2czNEX2dncGxvdFZvbGNfbGFiZWxzLnN2ZykNCg0KYGBge3IgR0dQTE9UIFZvbGNhbm8gT3ZlcmxheSBhbmQgU3BlY2lmaWMgTGFiZWxpbmcgMywgaW5jbHVkZT1GQUxTRX0NCiMtLS0tLS0tLS0tLS0tLS0tLU9WRVJMQVkgTEFCRUxFRCBHRU5FUy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KU2VsZWN0ZWRfZ2VuZXMgPC0gcmVzZGRzQ1BNVk9MQy5kZiAlPiUNCiAgZmlsdGVyKGdlbmVJRCAlaW4lIGMoIklMMzIiLCAiSUwzNCIsICJJTDFCIiwgIkNPTDdBMSIsICJDT0wxMEExIiwgIk1NUDEzIiwgIkxBTUMyIiwgIkxBTUIzIiwgIkNPTDI0QTEiLCAiTEFNQTEiLCAiVklUIikpDQpVUF9TZWxlY3RlZF9nZW5lcyA8LSByZXNkZHNDUE1WT0xDLmRmICU+JQ0KICBmaWx0ZXIoZ2VuZUlEICVpbiUgYygiSUwzMiIsICJJTDM0IiwgIklMMUIiLCAiQ09MN0ExIiwgIkNPTDEwQTEiLCAiTU1QMTMiLCAiTEFNQzIiLCAiTEFNQjMiKSkNCkRPV05fU2VsZWN0ZWRfZ2VuZXMgPC0gcmVzZGRzQ1BNVk9MQy5kZiAlPiUNCiAgZmlsdGVyKGdlbmVJRCAlaW4lIGMoIkNPTDI0QTEiLCAiTEFNQTEiLCAiVklUIikpDQoNCmdncGxvdFZvbGNfbGFiZWxzIDwtIGdncGxvdChkYXRhID0gcmVzZGRzQ1BNVk9MQy5kZiwNCiAgICAgICBhZXMoeCA9IGxvZzJGb2xkQ2hhbmdlLCB5ID0gLWxvZzEwKHBhZGopKSkgKyANCiAgICAgICBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPSBkaWZmZXhwcmVzc2VkKSwgDQogICAgICAgICAgICAgYWxwaGEgPSAwLjIsIA0KICAgICAgICAgICAgIHNoYXBlID0gMTYsDQogICAgICAgICAgICAgc2l6ZSA9IDEpICsgDQogIGdlb21fcG9pbnQoZGF0YSA9IFVQX1NlbGVjdGVkX2dlbmVzLA0KICAgICAgICAgICAgIHNoYXBlID0gMjEsDQogICAgICAgICAgICAgc2l6ZSA9IDIsIA0KICAgICAgICAgICAgIGZpbGwgPSAic3RlZWxibHVlIiwgDQogICAgICAgICAgICAgY29sb3VyID0gImJsYWNrIikgKyANCiAgZ2VvbV9wb2ludChkYXRhID0gRE9XTl9TZWxlY3RlZF9nZW5lcywNCiAgICAgICAgICAgICBzaGFwZSA9IDIxLA0KICAgICAgICAgICAgIHNpemUgPSAyLCANCiAgICAgICAgICAgICBmaWxsID0gImZpcmVicmljazMiLCANCiAgICAgICAgICAgICBjb2xvdXIgPSAiYmxhY2siKSArIA0KICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gLWxvZzEwKDAuMDUpLA0KICAgICAgICAgICAgIGxpbmV0eXBlID0gImRhc2hlZCIpICsgDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMobG9nMigwLjUpLCBsb2cyKDIpKSwNCiAgICAgICAgICAgICBsaW5ldHlwZSA9ICJkYXNoZWQiKSArDQogIGdlb21fbGFiZWxfcmVwZWwoZGF0YSA9IFNlbGVjdGVkX2dlbmVzLCAjIEFkZCBsYWJlbHMgbGFzdCB0byBhcHBlYXIgYXMgdGhlIHRvcCBsYXllciAgDQogICAgICAgICAgICAgICAgICAgYWVzKGxhYmVsID0gZ2VuZUlEKSwNCiAgICAgICAgICAgICAgICAgICBmb3JjZSA9IDIsDQogICAgICAgICAgICAgICAgICAgbnVkZ2VfeSA9IDMsDQogICAgICAgICAgICAgICAgICAgI2RpcmVjdGlvbiA9ICJ5IiwNCiAgICAgICAgICAgICAgICAgICBzaXplID0gMiwNCiAgICAgICAgICAgICAgICAgICBtaW4uc2VnbWVudC5sZW5ndGggPSB1bml0KDAsICJsaW5lcyIpLA0KICAgICAgICAgICAgICAgICAgIGxhYmVsLnBhZGRpbmcgPSB1bml0KDAuMiwgImxpbmVzIikpICsNCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjb2xzKSArIA0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gYyhzZXEoLTEwLCAxMCwgMikpLCAgICAgDQogICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKC0xMCwgMTApKSArDQogIHZvbGNfdGhlbWUNCg0KZ2dwbG90Vm9sY19sYWJlbHMNCiNnZ3NhdmUoIjJEdnMzRF9nZ3Bsb3RWb2xjX2xhYmVscy5zdmciLCBnZ3Bsb3RWb2xjX2xhYmVscywgd2lkdGggPSAzLjgsIGhlaWdodCA9IDIuNSwgdW5pdHMgPSAiaW4iLCBzY2FsZSA9IDIpDQpgYGANCg0KPGJyPg0KQWx0ZXJuYXRpdmVseSwgaXQgaXMgcG9zc2libGUgdG8gYXNzZW1ibGUgYSAqKk1BIHBsb3QqKiwgd2hpY2ggY29udmV5cyBhIHNpbWlsYXIgb3ZlcnZpZXcgdG8gKipWb2xjYW5vIHBsb3RzKiouIEhvd2V2ZXIsIHRoaXMgcGxvdCBsYWNrcyB0aGUgZGVzaWduIGZsZXhpYmlsaXR5IHRoYXQgVm9sY2FubyBwbG90cyBvZmZlciB0aHJvdWdoIHRoZWlyIGRlZGljYXRlZCBSIHBhY2thZ2VzLg0KDQpgYGB7ciBBbHRlcm5hdGl2ZSAyRCBNQSBQTE9UfQ0KI0FsdGVybmF0aXZlIHRvIFZvbGNhbm8gLSBNQSBQbG90LiBMZXNzIGZsZXhpYmlsaXR5IGluIGN1c3RvbWl6aW5nIHRoZSBmaW5hbCBmaWd1cmUuDQpNQVBsb3RfZGRzIDwtIERFU2VxMjo6cGxvdE1BKHJlc2Rkc0NQTSwgYWxwaGEgPSAwLjA1LCAjU2V0IHAtdmFsdWUgY3V0LW9mZiB0aHJlc2hvbGQuDQogICAgICAgICAgICAgICBjb2xOb25TaWcgPSAiZ3JheTMwIiwgICAgICAgICAgICAgICAgICAjU2V0IGNvbG9yIGNvZGUgZm9yIE5vbi1ERUcuDQogICAgICAgICAgICAgICBjb2xTaWcgPSAicm95YWxibHVlMyIsICAgICAgICAgICAgICAgICAjU2V0IGNvbG9yIGNvZGUgZm9yIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQuDQogICAgICAgICAgICAgICB5bGltID0gYygtNywgNykpICAgICAgICAgICAgICAgICAgICAgICAjU2V0IHktYXhpcyBsaW1pdC4NCmFibGluZShoID0gYygxLCAtMSksIGx0eSA9IDIpICAgICAgICAgICAgICAgICAgICAgICAgICNEcmF3IGhvcml6b250YWwgbGluZXMgYXQgdGhlIHNwZWNpZmllZCB5LWF4aXMgdmFsdWVzLCBsaW5lIHR5cGUgLSBkYXNoZWQuDQpgYGANCjxicj4NCkFwYXJ0IGZyb20gKipWb2xjYW5vIHBsb3RzKiosICoqSGVhdG1hcHMqKiBwcm92aWRlIGFuIGltcG9ydGFudCB2aXN1YWxpemF0aW9uIHRvb2wgaW4gUk5BU2VxIGZvciBkZXRlY3RpbmcgZ2VuZSBleHByZXNzaW9uIHRyZW5kcyBhbmQgaGlnaGxpZ2h0aW5nIGdlbmVzIHdpdGggcmVsZXZhbnQgYmlvbG9naWNhbCBmdW5jdGlvbnMuIEhlcmVpbiwgZWFjaCBzYW1wbGUgaXMgYXNzaWduZWQgdG8gYSBjb2x1bW4sIGFuZCBlYWNoIHJvdyBjb3JyZXNwb25kcyB0byBhICoqREVHKiogd2l0aCAqKmNvbG9yLWNvZGVkIGV4cHJlc3Npb24gbGV2ZWwqKi4gRXhwcmVzc2lvbiB2YWx1ZXMgYXJlIHR5cGljYWxseSBub3JtYWxpemVkIGFuZCB0cmFuc2Zvcm1lZCAoaS5lLiwgKipyb3cgei1zY2FsaW5nKiopIHRvIGVuc3VyZSB0aGF0IGdlbmVzIHdpdGggdmFyeWluZyBleHByZXNzaW9uIGxldmVscyBjYW4gYmUgY29tcGFyZWQgZWFzaWx5LiAqKkhlYXRtYXBzKiogYXJlIHVzdWFsbHkgcGFpcmVkIHdpdGggKipoaWVyYXJjaGljYWwgY2x1c3RlcmluZyoqIGFsZ29yaXRobXMgKGUuZy4sIFBlYXJzb24ncykgdGhhdCBncm91cCB0b2dldGhlciBnZW5lcyBhbmQgc2FtcGxlcyB3aXRoIHNpbWlsYXIgZXhwcmVzc2lvbiBwcm9maWxlcywgZ2VuZXJhdGluZyBhIGhpZXJhcmNoaWNhbCB0cmVlLWxpa2UgZGVuZHJvZ3JhbS4gKipIZWF0bWFwcyoqIGFyZSB0aHVzIHVzZWZ1bCBpbiBSTkFTZXEgZG93bnN0cmVhbSBhbmFseXNpcyBmb3IgcmV2ZWFsaW5nICoqY28tZXhwcmVzc2lvbiBwYXR0ZXJucyoqIGFuZCAqKmJpb2xvZ2ljYWwgZnVuY3Rpb25zKiogYWZmZWN0ZWQgYnkgZXhwZXJpbWVudGFsIGNvbmRpdGlvbnMuDQoNCg0KYGBge3IgSGVhdG1hcCBzZXR1cCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiNUcmFuc2Zvcm1hdGlvbiBvZiBkYXRhIGZvciBIZWF0bWFwDQp2c2RhdGEgPC0gdnN0KGRkc0NQTSwgYmxpbmQgPSBGQUxTRSkgICAgICAgICNBcHBseSB2YXJpYW5jZS1zdGFiaWxpemluZyB0cmFuc2Zvcm1hdGlvbi4NCnZzdF9tYXQgPC0gYXNzYXkodnNkYXRhKSAgICAgICAgICAgICAgICAgICAgI0NyZWF0ZSBtYXRyaXggd2l0aCB0cmFuc2Zvcm1lZCBnZW5lIGV4cHJlc3Npb24gdmFsdWVzLg0KdnN0X21hdCA8LSB2c3RfbWF0W3Jvd25hbWVzKHNpZ3NBTEwuZGYpLCBdICAjU3Vic2V0IG1hdHJpeCB0byBpbmNsdWRlIG9ubHkgREVHUywgaS5lLiwgcm93cyB0aGF0IG1hdGNoIGdlbmVzIGxpc3RlZCBpbiAnc2lnc0FMTC5kZicuDQpHZW5lbmFtZSA8LSBtYXBJZHMob3JnLkhzLmVnLmRiLCAgICAgICAgICAgICNNYXAgRW5zZW1ibCBJRCBmcm9tIG1hdHJpeCB0byBHZW5lIFN5bWJvbCBhbmQgc3RvcmUgaW4gdmFyaWFibGUgJ0dlbmVuYW1lJy4NCiAgICAgICAgICAgICAgIGtleXMgPSByb3cubmFtZXModnN0X21hdCksDQogICAgICAgICAgICAgIGtleXR5cGUgPSAiRU5TRU1CTCIsDQogICAgICAgICAgICAgIGNvbHVtbiA9ICJTWU1CT0wiKQ0KDQojUmVwbGFjZSBOQSBnZW5lIHN5bWJvbHMgd2l0aCBFTlNFTUJMIElEcyBpbiB2c3RfbWF0Lg0KIyhpKSBJZGVudGlmeSB3aGljaCBlbnRyaWVzIGluICdHZW5lbmFtZScgaGF2ZSBtaXNzaW5nIHZhbHVlcyAoTkEpLg0Kbm9fc3ltYm9sX2lkeCA8LSBpcy5uYShHZW5lbmFtZSkNCg0KIyhpaSkgRm9yICdHZW5lbmFtZScgZW50cmllcyB3aXRoIE5BLCByZXBsYWNlIHZhbHVlcyB3aXRoIG9yaWdpbmFsIEVuc2VtYmwgSUQgZXh0cmFjdGVkIGZyb20gJ3ZzdF9tYXQnIHJvdyBuYW1lcy4NCkdlbmVuYW1lW25vX3N5bWJvbF9pZHhdIDwtIHJvdy5uYW1lcyh2c3RfbWF0KVtub19zeW1ib2xfaWR4XQ0KDQojKGlpaSkgQ29udmVydCAnR2VuZW5hbWUnIHZlY3RvciBpbnRvIGEgc2luZ2xlIGNvbHVtbiBkYXRhLmZyYW1lLCBtYWtpbmcgaXQgc3VpdGFibGUgZm9yIGFzc2lnbm1lbnQgdG8gcm93IG5hbWVzIG9mICd2c3RfbWF0Jw0KRU5TX2dlbmVJRHMgPC0gc3RhY2soR2VuZW5hbWUpICAgICAgIA0KDQojKGl2KSBSZXBsYWNlIEVuc2VtYmwgSUQgZW50cmllcyB3aXRoIEdlbmUgU3ltYm9scyB3aGVuIGF2YWlsYWJsZSwgYW5kIHJldGFpbnMgb3JpZ2luYWwgRW5zZW1ibCBJRCBpZiBOQS4NCnJvdy5uYW1lcyh2c3RfbWF0KSA8LSBFTlNfZ2VuZUlEcyR2YWx1ZXMgICAgICAgICAgICAgICAgICAgICAgDQoNCg0KI0RvdWJsZS1jaGVjayB0aGF0IG5vIERFR3Mgd2VyZSBsb3N0IGR1cmluZyBhc3NpZ25tZW50DQojZGltKHZzdF9tYXQpICM1NjggREVHcyAtPiBUUlVFDQoNCiNTY2FsZSBnZW5lcyB6LXNjb3JlIGJ5IHJvdywgYXMgb3RoZXJ3aXNlIGxhcmdlIHZhbHVlcyBmcm9tIGhpZ2hseSBleHByZXNzZWQgZ2VuZXMgd291bGQgZG9taW5hdGUgdGhlIHBsb3QNCnZzdF9tYXRfeiA8LSB0KHNjYWxlKHQodnN0X21hdCkpKQ0KDQojQXNzaWduIGNvbHVtbiBuYW1lcyB0byBlYWNoIHNhbXBsZQ0KY29sbmFtZXModnN0X21hdF96KSA8LSBjKCIyREMxIiwgIjJEQzIiLCAiMkRDMyIsICIyREM0IiwgIjJEQzUiLCAiMkRHMSIsICIyREcyIiwgIjJERzMiLCAiMkRHNCIsICIyREc1IikNCg0KI0hlYXRtYXAgcGFyYW1ldGVycw0KY29sX2Z1biA8LSBjb2xvclJhbXAyKGMoLTIsIDAsIDIpLCAgICAgICAgICAgICAgICAgICAgICAgICNDcmVhdGUgc2VnbWVudHMgZm9yIHRoZSBjb2xvciBncmFkaWVudC4NCiAgICAgICAgICAgICAgICBjKCIjMjE2NkFDIiwgIndoaXRlIiwgIiNCMjE4MkIiKSkgICAjQ3JlYXRlIGNvbG9yIGdyYWRpZW50IHdpdGggdGhlIHNwZWNpZmllZCBjb2xvciBjb2Rlcy4NCg0KbGdkX2xpc3QgPC0gbGlzdCh0aXRsZSA9ICJaLXNjb3JlIiwgICAgICAgICAgICAgICAgICAgICAgICNTZXQgbGVnZW5kIHRpdGxlLg0KICAgICAgICAgICAgICAgIGxlZ2VuZF9oZWlnaHQgPSB1bml0KDIuNSwgImNtIiksICAgICAgICAgICNTZXQgaGVpZ2h0IG9mIHRoZSBsZWdlbmQgYm9keS4NCiAgICAgICAgICAgICAgICBncmlkX3dpZHRoID0gdW5pdCgwLjQsICJjbSIpLCAgICAgICAgICAgICAjU2V0IHdpZHRoIG9mIGVhY2ggbGVnZW5kIGdyaWQuDQogICAgICAgICAgICAgICAgdGl0bGVfcG9zaXRpb24gPSAidG9wY2VudGVyIiwgICAgICAgICAgICAgI1NldCBwb3NpdGlvbiBvZiB0aGUgdGl0bGUuDQogICAgICAgICAgICAgICAgZ2FwID0gdW5pdCg0LCAibW0iKSkgICAgICAgICAgICAgICAgICAgICAgI1NldCBnYXAgYmV0d2VlbiBoZWF0bWFwIGFuZCBsZWdlbmQuDQpgYGANCg0KDQpgYGB7ciBPdXRwdXQgSGVhdG1hcCwgZWNobz1UUlVFLCByZXN1bHRzPSdoaWRlJ30NCiNPdXRwdXQgZnVsbCBERUdzIEhlYXRtYXANCmh0IDwtIEhlYXRtYXAodnN0X21hdF96LCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjTWF0cml4IGlucHV0IGZvciBoZWF0bWFwLg0KICAgICAgICBjb2wgPSBjb2xfZnVuLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNTZXQgdmVjdG9yIG9mIGNvbG9ycyBmb3IgaW50ZXJwb2xhdGlvbi4NCiAgICAgICAgc2hvd19jb2x1bW5fbmFtZXMgPSBGQUxTRSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjV2hldGhlciB0byBzaG93IGNvbHVtbiBsYWJlbGluZy4gDQogICAgICAgIHNob3dfcm93X25hbWVzID0gRkFMU0UsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI1doZXRoZXIgdG8gc2hvdyByb3cgbGFiZWxpbmcuDQogICAgICAgICNyb3dfbGFiZWxzID0gc2lncy5kZltyb3duYW1lcyh2c3RfbWF0X3opLF0kU3ltYm9sLCAgICAgI1VuY29tbWVudCB0byBzcGVjaWZ5IHJvdyBsYWJlbGluZy4gDQogICAgICAgIHJvd19uYW1lc19ncCA9IGdwYXIoZm9udHNpemUgPSA1KSwgICAgICAgICAgICAgICAgICAgICAgI1NldCBmb250IHNpemUgZm9yIHJvdyBsYWJlbGluZy4NCiAgICAgICAgY2x1c3RlcmluZ19kaXN0YW5jZV9jb2x1bW5zID0gInBlYXJzb24iLCAgICAgICAgICAgICAgICAjU2V0IGNsdXN0ZXJpbmcgbWV0aG9kIGZvciBjb2x1bW4gZGVuZHJvZ3JhbS4NCiAgICAgICAgY2x1c3RlcmluZ19kaXN0YW5jZV9yb3dzID0gInBlYXJzb24iLCAgICAgICAgICAgICAgICAgICAjU2V0IGNsdXN0ZXJpbmcgbWV0aG9kIGZvciByb3cgZGVuZHJvZ3JhbS4NCiAgICAgICAgI2NvbHVtbl9sYWJlbHMgPSBjb2xuYW1lcyh2c3RfbWF0X3opLCAgICAgICAgICAgICAgICAgICAjVW5jb21tZW50IGZvciBzcGVjaWZ5aW5nIGNvbHVtbiBsYWJlbGluZy4gDQogICAgICAgIGNvbHVtbl9uYW1lc19ncCA9IGdwYXIoZm9udHNpemUgPSA1KSwgICAgICAgICAgICAgICAgICAgI1NldCBmb250IHNpemUgZm9yIGNvbHVtbiBsYWJlbGluZy4NCiAgICAgICAgcm93X2RlbmRfcmVvcmRlciA9IEZBTFNFLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjV2hldGhlciB0byBhcHBseSByb3cgZGVuZHJvZ3JhbSByZW9yZGVyaW5nLiANCiAgICAgICAgY29sdW1uX2RlbmRfcmVvcmRlciA9IFRSVUUsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjV2hldGhlciB0byBhcHBseSBjb2x1bW4gZGVuZHJvZ3JhbSByZW9yZGVyaW5nLiANCiAgICAgICAgc2hvd19yb3dfZGVuZCA9IFRSVUUsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjV2hldGhlciB0byBzaG93IHJvdyBkZW5kcm9ncmFtIGNsdXN0ZXJpbmcuDQogICAgICAgIHJvd19kZW5kX3dpZHRoID0gdW5pdCgxMCwgIm1tIiksICAgICAgICAgICAgICAgICAgICAgICAgI1NldCB3aWR0aCBvZiByb3cgZGVuZHJvZ3JhbXMuDQogICAgICAgIHNob3dfY29sdW1uX2RlbmQgPSBGQUxTRSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI1doZXRoZXIgdG8gc2hvdyBjb2x1bW4gZGVuZHJvZ3JhbSBjbHVzdGVyaW5nLg0KICAgICAgICB3aWR0aCA9IHVuaXQoMiwgImluIiksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNTZXQgaGVhdG1hcCB3aWR0aC4NCiAgICAgICAgaGVpZ2h0ID0gdW5pdCgxMCwgImluIiksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjU2V0IGhlYXRtYXAgaGVpZ2h0Lg0KICAgICAgICBuYW1lID0gIlotc2NvcmUiKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNTZXQgdGl0bGUuDQojaHQNCiN0aWZmKCIyRF9GdWxsX0hlYXRtYXAudGlmZiIsIHdpZHRoID0gNCwgaGVpZ2h0ID0gMTAsIHVuaXRzID0gImluIiwgcmVzPTYwMCkNCiNkcmF3KGh0KQ0KI2Rldi5vZmYoKQ0KYGBgDQoNCiFbXShUcmVhdGVkLzJEX0Z1bGxfSGVhdG1hcC5zdmcpDQoNCg0KDQo8YnI+DQo8YnI+DQpOZXh0LCBpdCBiZWNvbWVzIGhpZ2hseSB2YWx1YWJsZSB0byB6b29tIGluIG9uICoqc3BlY2lmaWMgZ2VuZSBzdWJzZXRzKiogdGhhdCBhcmUgaW52b2x2ZWQgaW4gcmVsZXZhbnQgKipiaW9sb2dpY2FsIHByb2Nlc3NlcyoqLiBIZXJlaW4sIERFR3MgcmVsYXRlZCB0byAqKmV4dHJhY2VsbHVsYXIgbWF0cml4IG9yZ2FuaXphdGlvbioqLCAqKmdseWNvcHJvdGVpbnMqKiBhbmQgKipzZWNyZXRlZCBmYWN0b3JzKiogYXJlIG1hcHBlZCB0byB1bnZlaWwgdGhlIGltcGFjdCBvZiB0aGUgY2VsbCBzdXJmYWNlIGVuZ2luZWVyaW5nIHByb2Nlc3Mgb24gdGhlIHRyYW5zY3JpcHRvbWUuDQoNCg0KYGBge3IgSGVhdG1hcCBTZWxlY3RlZCBTdWJzZXQgb2YgR2VuZXMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHJlc3VsdHM9J2hpZGUnLCBmaWcua2VlcD0nYWxsJ30NCiNDcmVhdGUgdmVjdG9ycyBvZiBnZW5lIGxpc3RzDQpHZW5lbGlzdF9FQ00gPSBjKCJBREFNVFMxNSIsICJXTlQxNiIsICJXTlQyIiwgIldOVDlBIiwgIkFOR1BUTDQiLCAiQk1QNCIsICJNTVJOMiIsICJDT0wyMUExIiwgIkNPTDIyQTEiLCAiT01EIiwgIlROWEIiLCAiVEhTRDQiKQ0KR2VuZWxpc3RfR2x5Y29wcm90ZWlucyA9IGMoIkFEQU1UUzE1IiwgIkFQQ0REMUwiLCAiQUJDQTYiLCAiQUJDQTgiLCAiQUJDQTkiLCAiQUJDQjYiLCAiQUJDQzIiLCAiQUJDQzMiLCAiQVRQNlYwRTIiLCAiQlJJTlAxIiwgIkNFQlBCIiwgIkNEMjAwIiwgIkVQSEE1IiwgIkZBTTIwQSIsICJHUFIxMzdCIiwgIkdQUjY4IiwgIkdQUkM1QSIsICJHUFJDNUIiLCAiS0NOSjUtQVMxIiwgIktJVExHIiwgIktJVCIsICJMSUYiLCAiTFlQRDEiLCAiTVBMIiwgIk5PWDQiLCAiU0hBTksyIiwgIlNMSVRSSzQiLCAiU1Q2R0FMTkFDNSIsICJTVDZHQUwyIiwgIkIzR05UOCIsICJXTlQxNiIsICJXTlQyIiwgIldOVDlBIiwgIkFEQ1k0IiwgIkFGUCIsICJNR0FUNEIiLCAiQVJFRyIsICJBTkdQVDEiLCAiQU5HUFRMNCIsICJBR1RSMSIsICJBUVAxIiwgIkFDS1IzIiwgIkIzR0FMVDIiLCAiQjRHQUxOVDEiLCAiQk1QNCIsICJDREgxOCIsICJDREg2IiwgIkNESDgiLCAiQ0hTVDYiLCAiQ0RPTiIsICJDRU1JUCIsICJDSFJNMiIsICJDU0dBTE5BQ1QxIiwgIkNPTDIxQTEiLCAiQ09MMjJBMSIsICJDMVJMIiwgIkNGSFIxIiwgIkNOTk00IiwgIkVOUFA0IiwgIkVMQVBPUjEiLCAiRVNNMSIsICJFRE5SQiIsICJFRk5BNSIsICJFUE9SIiwgIkdSUFIiLCAiR1BDMSIsICJHREYxNSIsICJHREY2IiwgIkhISVAiLCAiSEdGIiwgIkhNTVIiLCAiSFNEMTFCMSIsICJJR1NGMTAiLCAiSUdGQlAzIiwgIklDQU0xIiwgIklGTkUiLCAiSUwxUkwxIiwgIklMMjBSQSIsICJJTDM0IiwgIkpVUCIsICJMUlJOMyIsICJMSVBHIiwgIk1FMSIsICJNWFJBNSIsICJNTVJOMiIsICJORE5GIiwgIk5FVE8yIiwgIk5PVENINCIsICJPTUQiLCAiUExBVCIsICJQREdGUkwiLCAiUExYREMxIiwgIkdBTE5UMTUiLCAiR0FMTlQzIiwgIlBPUERDMyIsICJLQ05LMSIsICJQQ1NLNiIsICJQQ1NLOSIsICJQVEdEUiIsICJQVEdFUjMiLCAiUFRHUzIiLCAiUFRQUlEiLCAiUENESEI1IiwgIlJBRVQxRSIsICJSTkYxMjgiLCAiUk5GMTUwIiwgIlNQUDEiLCAiU0VNQTNDIiwgIlNFTUEzRCIsICJTRU1BNkQiLCAiUFJTUzM1IiwgIlNOQUkxIiwgIlNMQzFBMiIsICJTTEMxMkE5IiwgIlNMQzE0QTEiLCAiU0xDMkExMiIsICJTTEMyQTUiLCAiU0xDMjRBMyIsICJTTEMzOEExIiwgIlNMQzM4QTQiLCAiU0xDNEE4IiwgIlNMQzdBMTEiLCAiU0xDN0ExNCIsICJUTlhCIiwgIlRFTk00IiwgIlRIQkQiLCAiVFJQQzYiLCAiVE1FTTEzMCIsICJWQ0FNMSIpDQpHZW5lbGlzdF9TZWNyZXRlZCA9IGMoIkFEQU1UUzE1IiwgIkFCQ0I2IiwgIkNDTDI2IiwgIkNYQ0wxIiwgIkNYQ0wyIiwgIkNYQ0wzIiwgIkNYQ0w2IiwgIkNYQ0w4IiwgIkMxUVRORjIiLCAiRkFNMjBBIiwgIkhUUkEzIiwgIktDTko1LUFTMSIsICJLSVRMRyIsICJMSUYiLCAiV05UMTYiLCAiV05UMiIsICJXTlQ5QSIsICJBS1IxQjEwIiwgIkFGUCIsICJBTkdQVDEiLCAiQU5HUFRMNCIsICJCTVA0IiwgIkNFTUlQIiwgIkNPTDIxQTEiLCAiQ09MMjJBMSIsICJDMVJMIiwgIkNGSFIxIiwgIkVTTTEiLCAiRUROMSIsICJFUE9SIiwgIkZBQlA1IiwgIkdQQzEiLCAiR0RGMTUiLCAiR0RGNiIsICJISElQIiwgIklHU0YxMCIsICJJR0ZCUDMiLCAiSUZORSIsICJJTDFCIiwgIklMMVJMMSIsICJJTDM0IiwgIkxJUEciLCAiTVhSQTUiLCAiTU1STjIiLCAiTkRORiIsICJPTUQiLCAiUElOTFlQIiwgIlBMQVQiLCAiUERHRlJMIiwgIlBMWERDMSIsICJQQ1NLNiIsICJQQ1NLOSIsICJSQUVUMUUiLCAiU1BQMSIsICJTQ0c1IiwgIlNFTUEzQyIsICJTRU1BM0QiLCAiUFJTUzM1IiwgIlROWEIiLCAiVEhTRDQiKQ0KDQojUmVwbGFjZSBoZXJlIFtHZW5lbGlzdF9FQ01dIHdpdGggdGhlIG5hbWUgb2YgdGhlIHZlY3RvciBmb3Igc3BlY2lmaWMgZ2VuZXMgYygiWFgiLCAiWFkiLCAiWFoiKQ0Kc2VsZWN0ZWRfREVHcyA8LSBHZW5lbGlzdF9TZWNyZXRlZA0KDQojRmlsdGVycyB0aGUgbWF0cml4IHRvIHJldGFpbiBvbmx5IHRoZSByb3dzIHRoYXQgY29ycmVzcG9uZCB0byB0aGUgZ2VuZXMgbGlzdGVkIGluICdzZWxlY3RlZF9ERUdzJyB2ZWN0b3IuDQp2c3RfbWF0U2VsZWN0ZWQgPC0gdnN0X21hdFtyb3duYW1lcyh2c3RfbWF0KSAlaW4lIHNlbGVjdGVkX0RFR3MsIF0NCg0KI0RvdWJsZSBjaGVjayB0byBlbnN1cmUgdGhhdCBhbGwgc2VsZWN0ZWQgREVHcyB3ZXJlIHJldHJpZXZlZA0KI2RpbSh2c3RfbWF0KSAgICAgICAgICAgICAgICAgICAgIzU2OCBERUdzDQojZGltKHZzdF9tYXRTZWxlY3RlZCkgICAgICAgICAgICAjNjAgREVHcw0KI2xlbmd0aChHZW5lbGlzdF9TZWNyZXRlZCkgICAgICAgIzYwIERFR3MNCg0KI0FwcGx5IHJvdyB6LXNjYWxpbmcNCnZzdF9tYXRTZWxlY3RlZF96IDwtIHQoc2NhbGUodCh2c3RfbWF0U2VsZWN0ZWQpKSkNCg0KI0Fzc2lnbiBjb2x1bW4gbmFtZXMgdG8gZWFjaCBzYW1wbGUNCmNvbG5hbWVzKHZzdF9tYXRTZWxlY3RlZF96KSA8LSBjKCIyREMxIiwgIjJEQzIiLCAiMkRDMyIsICIyREM0IiwgIjJEQzUiLCAiMkRHMSIsICIyREcyIiwgIjJERzMiLCAiMkRHNCIsICIyREc1IikNCg0KI0hlYXRtYXAgcGFyYW1ldGVycw0KY29sX2Z1biA8LSBjb2xvclJhbXAyKGMoLTIsIDAsIDIpLCAgICAgICAgICAgICAgICAgICAgICAgICNDcmVhdGUgc2VnbWVudHMgZm9yIHRoZSBjb2xvciBncmFkaWVudC4NCiAgICAgICAgICAgICAgICAgICAgICBjKCIjMjE2NkFDIiwgIndoaXRlIiwgIiNCMjE4MkIiKSkgICAjQ3JlYXRlIGNvbG9yIGdyYWRpZW50IHdpdGggdGhlIHNwZWNpZmllZCBjb2xvciBjb2Rlcy4NCg0KbGdkX2xpc3QgPC0gbGlzdCh0aXRsZSA9ICJaLXNjb3JlIiwgICAgICAgICAgICAgICAgICAgICAgICNTZXQgbGVnZW5kIHRpdGxlLg0KICAgICAgICAgICAgICAgIHRpdGxlX2dwID0gZ3Bhcihmb250c2l6ZSA9IDEyKSwgICAgICAgICAgICNTZXQgZm9udCBzaXplIGZvciBsZWdlbmQgdGl0bGUuDQogICAgICAgICAgICAgICAgbGVnZW5kX2hlaWdodCA9IHVuaXQoMi41LCAiY20iKSwgICAgICAgICAgI1NldCBoZWlnaHQgb2YgdGhlIGxlZ2VuZCBib2R5Lg0KICAgICAgICAgICAgICAgIGxlZ2VuZF93aWR0aCA9IHVuaXQoNSwgImNtIiksICAgICAgICAgICAgICNTZXQgd2lkdGggb2YgdGhlIGxlZ2VuZCBib2R5Lg0KICAgICAgICAgICAgICAgIGdyaWRfd2lkdGggPSB1bml0KDAuNCwgImNtIiksICAgICAgICAgICAgICNTZXQgd2lkdGggb2YgZWFjaCBsZWdlbmQgZ3JpZC4NCiAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsICAgICAgICAgICAgICAgICAjV2hldGhlciBzY2FsZSBpcyAnaG9yaXpvbnRhbCcgb3IgJ3ZlcnRpY2FsJw0KICAgICAgICAgICAgICAgIHRpdGxlX3Bvc2l0aW9uID0gInRvcGNlbnRlciIsICAgICAgICAgICAgICNTZXQgcG9zaXRpb24gb2YgdGhlIHRpdGxlLg0KICAgICAgICAgICAgICAgIGdhcCA9IHVuaXQoNCwgIm1tIikpICAgICAgICAgICAgICAgICAgICAgICNTZXQgZ2FwIGJldHdlZW4gaGVhdG1hcCBhbmQgbGVnZW5kLg0KDQoNCmh0X3NlbGVjdGVkIDwtIEhlYXRtYXAodnN0X21hdFNlbGVjdGVkX3osICAgICAgICAgICAgICAgICAjTWF0cml4IGlucHV0IGZvciBoZWF0bWFwLg0KICAgICAgICBjb2wgPSBjb2xfZnVuLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNWZWN0b3Igb2YgY29sb3JzIGZvciBpbnRlcnBvbGF0aW9uLg0KICAgICAgICByZWN0X2dwID0gZ3Bhcihjb2wgPSAiZ3JleTMwIiwgbHdkID0gMC4xNSksICAgICAgICNCb3JkZXIgbGluZSBjb2xvciBhbmQgd2lkdGggb2YgZWFjaCBjZWxsLg0KICAgICAgICBzaG93X2NvbHVtbl9uYW1lcyA9IEZBTFNFLCAgICAgICAgICAgICAgICAgICAgICAgICNXaGV0aGVyIHRvIHNob3cgY29sdW1uIGxhYmVsaW5nLg0KICAgICAgICBzaG93X3Jvd19uYW1lcyA9IFRSVUUsICAgICAgICAgICAgICAgICAgICAgICAgICAgICNXaGV0aGVyIHRvIHNob3cgcm93IGxhYmVsaW5nLg0KICAgICAgICByb3dfbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplID0gNSksICAgICAgICAgICAgICAgICNTZXQgZm9udCBzaXplIGZvciByb3cgbGFiZWxpbmcuDQogICAgICAgIGNsdXN0ZXJpbmdfZGlzdGFuY2VfY29sdW1ucyA9ICJwZWFyc29uIiwgICAgICAgICAgI1NldCBjbHVzdGVyaW5nIG1ldGhvZCBmb3IgY29sdW1uIGRlbmRyb2dyYW0uDQogICAgICAgIGNsdXN0ZXJpbmdfZGlzdGFuY2Vfcm93cyA9ICJwZWFyc29uIiwgICAgICAgICAgICAgI1NldCBjbHVzdGVyaW5nIG1ldGhvZCBmb3Igcm93IGRlbmRyb2dyYW0uDQogICAgICAgICNjb2x1bW5fbGFiZWxzID0gY29sbmFtZXModnN0X21hdFNlbGVjdGVkX3opLCAgICAgI1VuY29tbWVudCB0byBzcGVjaWZ5IGNvbHVtbiBsYWJlbGluZy4NCiAgICAgICAgY29sdW1uX25hbWVzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDUpLCAgICAgICAgICAgICAjU2V0IGZvbnQgc2l6ZSBmb3IgY29sdW1uIGxhYmVsaW5nLg0KICAgICAgICByb3dfZGVuZF9yZW9yZGVyID0gRkFMU0UsICAgICAgICAgICAgICAgICAgICAgICAgICNXaGV0aGVyIHRvIGFwcGx5IHJvdyBkZW5kcm9ncmFtIHJlb3JkZXJpbmcuDQogICAgICAgIGNvbHVtbl9kZW5kX3Jlb3JkZXIgPSBUUlVFLCAgICAgICAgICAgICAgICAgICAgICAgI1doZXRoZXIgdG8gYXBwbHkgY29sdW1uIGRlbmRyb2dyYW0gcmVvcmRlcmluZy4gDQogICAgICAgIHNob3dfcm93X2RlbmQgPSBGQUxTRSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgI1doZXRoZXIgdG8gc2hvdyByb3cgZGVuZHJvZ3JhbSBjbHVzdGVyaW5nLg0KICAgICAgICByb3dfZGVuZF93aWR0aCA9IHVuaXQoMTAsICJtbSIpLCAgICAgICAgICAgICAgICAgICNTZXQgd2lkdGggb2Ygcm93IGRlbmRyb2dyYW1zLg0KICAgICAgICBzaG93X2NvbHVtbl9kZW5kID0gRkFMU0UsICAgICAgICAgICAgICAgICAgICAgICAgICNXaGV0aGVyIHRvIHNob3cgY29sdW1uIGRlbmRyb2dyYW0gY2x1c3RlcmluZy4NCiAgICAgICAgd2lkdGggPSB1bml0KDMsICJpbiIpLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAjU2V0IGhlYXRtYXAgd2lkdGguDQogICAgICAgIGhlaWdodCA9IHVuaXQoMy41LCAiaW4iKSwgICAgICAgICAgICAgICAgICAgICAgICAgI1NldCBoZWF0bWFwIGhlaWdodC4NCiAgICAgICAgaGVhdG1hcF9sZWdlbmRfcGFyYW0gPSBsZ2RfbGlzdCwgICAgICAgICAgICAgICAgICAjUmVmZXJlbmNlIG9iamVjdCBmb3IgbGVnZW5kIHBhcmFtZXRlcnMuDQogICAgICAgICNzaG93X2hlYXRtYXBfbGVnZW5kID0gRkFMU0UsICAgICAgICAgICAgICAgICAgICAgI1VuY29tbWVudCB0byBoaWRlIGhlYXRtYXAgbGVnZW5kLg0KICAgICAgICBuYW1lID0gIlotc2NvcmUiKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNTZXQgdGl0bGUuDQoNCmh0X3NlbGVjdGVkID0gZHJhdyhodF9zZWxlY3RlZCwgaGVhdG1hcF9sZWdlbmRfc2lkZSA9ICJib3R0b20iKSAjRHJhd3MgaGVhdG1hcCB3aXRoIGxlZ2VuZCBhdCB0aGUgYm90dG9tIHBvc2l0aW9uLg0KDQojT3V0cHV0IHNldHRpbmdzIGZvciBlYWNoIGhlYXRtYXAgKFcgPSB3aWR0aCwgSCA9IGhlaWdodCkNCiMyRF9FQ006IFcgPSAzIHggSCA9IDMuNSB8IE91dHB1dCBzdmc6IFcgPSA1IHggSCA9IDUNCiMyRF9TZWNyZXRlZDogVyA9IDMgeCBIID0gNi41IHwgT3V0cHV0IHN2ZzogVyA9IDQgeCBIID0gNC41DQojMkRfR2x5Y29wcm90ZWluczogVyA9IDMgeCBIID0gMy41IHwgT3V0cHV0IHN2ZzogVyA9IDQgeCBIID0gNC41DQoNCnN2ZyhmaWxlbmFtZSA9ICIyRF9IZWF0bWFwX1NlY3JldGVkLnN2ZyIsIHdpZHRoID0gNCwgaGVpZ2h0ID0gNC41KQ0KZHJhdyhodF9zZWxlY3RlZCwgaGVhdG1hcF9sZWdlbmRfc2lkZSA9ICJib3R0b20iKQ0KZGV2Lm9mZigpDQpgYGANCg0KDQpgYGB7ciByb3dBbm5vdGF0aW9uIHRvIGJlIHVzZWQgd2l0aGluIHJpZ2h0X2Fubm90YXRpb24gbm90IHdvcmtpbmcgeWV0LCBpbmNsdWRlPUZBTFNFfQ0KI2hhID0gcm93QW5ub3RhdGlvbihmb28gPSBhbm5vX21hcmsoYXQgPSBtYXJrX2F0LCBsYWJlbHMgPSBHZW5lc19Eb3VibGVDaGVjaywNCiAgICAgICAgICAgICAgICAgICNsaW5rX3dpZHRoID0gdW5pdCg1LCAibW0iKSwNCiAgICAgICAgICAgICAgICAgICNwYWRkaW5nID0gMC41LA0KIyAgICAgICAgICAgICAgICAgIGxhYmVsc19ncCA9IGdwYXIoZm9udHNpemUgPSAxMA0KICAgICAgICAgICAgICAgICAgICAgIywgZm9udGZhY2UgPSAiYm9sZCIgIA0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSkpDQojaGEgPSByb3dBbm5vdGF0aW9uKGZvbyA9IGFubm9fbWFyayhhdCA9IHdoaWNoKHJvd25hbWVzKHZzdF9tYXRTZWxlY3RlZF96KSAlaW4lIEdlbmVzX0xhYmVsKSwNCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSByb3duYW1lcyh2c3RfbWF0U2VsZWN0ZWRfeilbcm93bmFtZXModnN0X21hdFNlbGVjdGVkX3opJWluJUdlbmVzX0xhYmVsXSwNCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoID0gInJvdyIpKQ0KYGBgDQoNCjxicj4NCkluIGxhcmdlICoqSGVhdG1hcHMqKiwgaW4gb3JkZXIgdG8gYXZvaWQgdmlzdWFsIGNsdXR0ZXJpbmcgYnkgbGFiZWxpbmcgZXZlcnkgZ2VuZSwgaXQgaXMgb2Z0ZW4gdmFsdWFibGUgdG8gbGFiZWwgb25seSBhIHN1YnNldCBvZiBnZW5lcy4NCg0KYGBge3IgSGVhdG1hcCBTcGVjaWZpYyBHZW5lIExhYmVsaW5nLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCByZXN1bHRzPSdoaWRlJywgZmlnLmtlZXA9J2xhc3QnfQ0KI0hlYXRtYXAgcGFyYW1ldGVycw0KY29sX2Z1biA8LSBjb2xvclJhbXAyKGMoLTIsIDAsIDIpLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAjQ3JlYXRlIHNlZ21lbnRzIGZvciB0aGUgY29sb3IgZ3JhZGllbnQuDQogICAgICAgICAgICAgICAgICAgICAgYygiIzIxNjZBQyIsICJ3aGl0ZSIsICIjQjIxODJCIikpICAgICAgICNDcmVhdGUgY29sb3IgZ3JhZGllbnQgd2l0aCB0aGUgc3BlY2lmaWVkIGNvbG9yIGNvZGVzLg0KDQpsZ2RfbGlzdCA8LSBsaXN0KHRpdGxlID0gIlotc2NvcmUiLCAgICAgICAgICAgICAgICAgICAgICAgICAgICNTZXQgbGVnZW5kIHRpdGxlLg0KICAgICAgICAgICAgICAgIHRpdGxlX2dwID0gZ3Bhcihmb250c2l6ZSA9IDEyKSwgICAgICAgICAgICAgICAjU2V0IGZvbnQgc2l6ZSBmb3IgbGVnZW5kIHRpdGxlLg0KICAgICAgICAgICAgICAgIGxlZ2VuZF9oZWlnaHQgPSB1bml0KDIuNSwgImNtIiksICAgICAgICAgICAgICAjU2V0IGhlaWdodCBvZiB0aGUgbGVnZW5kIGJvZHkuDQogICAgICAgICAgICAgICAgbGVnZW5kX3dpZHRoID0gdW5pdCg1LCAiY20iKSwgICAgICAgICAgICAgICAgICNTZXQgd2lkdGggb2YgdGhlIGxlZ2VuZCBib2R5Lg0KICAgICAgICAgICAgICAgIGdyaWRfd2lkdGggPSB1bml0KDAuNCwgImNtIiksICAgICAgICAgICAgICAgICAjU2V0IHdpZHRoIG9mIGVhY2ggbGVnZW5kIGdyaWQuDQogICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gImhvcml6b250YWwiLCAgICAgICAgICAgICAgICAgICAgICNXaGV0aGVyIHNjYWxlIGlzICdob3Jpem9udGFsJyBvciAndmVydGljYWwnDQogICAgICAgICAgICAgICAgdGl0bGVfcG9zaXRpb24gPSAidG9wY2VudGVyIiwgICAgICAgICAgICAgICAgICNTZXQgcG9zaXRpb24gb2YgdGhlIHRpdGxlLg0KICAgICAgICAgICAgICAgIGdhcCA9IHVuaXQoNCwgIm1tIikpICAgICAgICAgICAgICAgICAgICAgICAgICAjU2V0IGdhcCBiZXR3ZWVuIGhlYXRtYXAgYW5kIGxlZ2VuZC4NCg0KDQojQ3JlYXRlIHZlY3RvciB3aXRoIHN1YnNldCBvZiBnZW5lcyB0byBsYWJlbA0KR2x5Y29wcm90ZWluc19zZWxlY3RfbGFiZWwgPSBjKCJBTkdQVDEiLCAiQjNHTlQ4IiwgIk1HQVQ0QiIsICJFRE5SQiIsICJORE5GIiwgIkFEQU1UUzE1IiwgIlNUNkdBTE5BQzUiLCAiQk1QNCIsICJDREg4IiwgIkNPTDIxQTEiLCAiSUwzNCIsICJJQ0FNMSIsICJOT1RDSDQiLCAiT01EIiwgIlNFTUEzRCIsICJWQ0FNMSIpDQpTZWNyZXRlZF9zZWxlY3RfbGFiZWwgPSBjKCJXTlQyIiwgIldOVDE2IiwgIkNYQ0wxIiwgIkNYQ0wyIiwgIkJNUDQiLCAiQ09MMjJBMSIsICJFRE4xIiwgIkdERjYiLCAiSUwxQiIsICJDRU1JUCIsICJMSVBHIiwgIlNDRzUiLCAiTVhSQTUiLCAiSUZORSIsICJTUFAxIiwgIkFOR1BUMSIsICJORE5GIiwgIktJVExHIiwgIkFLUjFCMTAiKQ0KDQojQXNzaWduIGdlbmVzIHN1YnNldCB0byBhIHN0YXRpYyBvYmplY3QgZm9yIGVhc2lseSBzd2l0Y2hpbmcgYmV0d2VlbiBwbG90cw0KR2VuZXNfTGFiZWwgPSBTZWNyZXRlZF9zZWxlY3RfbGFiZWwNCg0KI0lkZW50aWZ5IGluZGljZXMgb2YgdGhlIHJvdyBuYW1lcyBpbiB0aGUgbWF0cml4IHRoYXQgY29ycmVzcG9uZCB0byB0aGUgZ2VuZXMgbGlzdGVkIGluIHRoZSB2ZWN0b3IgJ0dlbmVzX0xhYmVsJyANCm1hcmtfYXQgPSB3aGljaChyb3duYW1lcyh2c3RfbWF0U2VsZWN0ZWRfeikgJWluJSBHZW5lc19MYWJlbCkNCg0KI0V4dHJhY3QgdGhlIHJvdyBuYW1lcyBvZiB0aGUgbWF0cml4IHRoYXQgY29ycmVzcG9uZCB0byBpbmRpY2VzIGluICdtYXJrX2F0Jy4gVGhpcyBzdGVwIGlzIGEgZG91YmxlLWNoZWNrIHRvIGVuc3VyZSB0aGF0IHRoZSBzZWxlY3RlZCByb3dzIGRvIGluZGVlZCBtYXRjaCB0aGUgb3JpZ2luYWwgJ0dlbmVzX0xhYmVsJyB2ZWN0b3IuDQpHZW5lc19Eb3VibGVDaGVjayA8LSByb3duYW1lcyh2c3RfbWF0U2VsZWN0ZWRfeilbbWFya19hdF0NCg0KI0NoZWNrIHdoZXRoZXIgdGhlIHR3byB2ZWN0b3JzIGNvbnRhaW4gdGhlIHNhbWUgZWxlbWVudHMsIHJlZ2FyZGxlc3Mgb2YgdGhlaXIgb3JkZXIuDQpzZXRlcXVhbChHZW5lc19Eb3VibGVDaGVjaywgR2VuZXNfTGFiZWwpICNUUlVFIC0+IHByb2NlZWQgdG8gbGFiZWxpbmcuDQoNCiNOb3RlOiBVc2UgJ0dlbmVzX0RvdWJsZUNoZWNrJyBvYmplY3QgZm9yIGxhYmVsaW5nLCBiZWNhdXNlIGl0IG91dHB1dHMgR2VuZSBzeW1ib2xzIGluIHRoZSBzYW1lIG9yZGVyIGFzICdtYXJrX2F0Jy4gVGhpcyBpcyBuZWNlc3NhcnkgYmVjYXVzZSAnbWFya19hdCcgZXh0cmFjdHMgcm93IG5hbWUgbnVtYmVycywgd2hpY2ggYXJlIGF1dG9tYXRpY2FsbHkgb3JkZXJlZCBudW1lcmljYWxseSBpbiB0aGUgb3V0cHV0IHZlY3Rvci4NCg0KIydhbm5vX21hcmsnIGZ1bmN0aW9uIGluIENvbXBsZXhIZWF0bWFwIHBhY2thZ2UgZW5hYmxlcyBsaW5raW5nIGhlYXRtYXAgYW5ub3RhdGlvbiB3aXRoIGN1c3RvbWl6ZWQgbGFiZWxzLg0KZm9vID0gYW5ub19tYXJrKGF0ID0gbWFya19hdCwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjTnVtZXJpYyBpbmRleCBmcm9tIG9yaWdpbmFsIG1hdHJpeC4NCiAgICAgICAgICAgICAgICAjbGlua193aWR0aCA9IHVuaXQoNSwgIm1tIiksICAgICAgICAgICAgICAgICAgI1VuY29tbWVudCB0byBzcGVjaWZ5IGxhYmVsIGxpbmsgd2lkdGguDQogICAgICAgICAgICAgICAgcGFkZGluZyA9IDAuNzUsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNQYWRkaW5nIHNwYWNlIGJldHdlZW4gbmVpZ2hib3JpbmcgbGFiZWxzLg0KICAgICAgICAgICAgICAgIGxhYmVscyA9IEdlbmVzX0RvdWJsZUNoZWNrLCAgICAgICAgICAgICAgICAgICAjQ29ycmVzcG9uZGluZyBsYWJlbHMuDQogICAgICAgICAgICAgICAgbGFiZWxzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDEwKSwgICAgICAgICAgICAgICNTZXRzIGZvbnQgc2l6ZS4NCiAgICAgICAgICAgICAgICB3aGljaCA9ICJyb3ciKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI1doZXRoZXIgJ2NvbHVtbicgb3IgJ3JvdycgYW5ub3RhdGlvbi4NCg0KaHRfc2VsZWN0ZWRfbGFiZWwgPC0gSGVhdG1hcCh2c3RfbWF0U2VsZWN0ZWRfeiwgICAgICAgICAgICAgICAjTWF0cml4IGlucHV0IGZvciBoZWF0bWFwLg0KICAgICAgICAgICAgICAgICBjb2wgPSBjb2xfZnVuLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjVmVjdG9yIG9mIGNvbG9ycyBmb3IgaW50ZXJwb2xhdGlvbi4NCiAgICAgICAgICAgICAgICAgcmVjdF9ncCA9IGdwYXIoY29sID0gImdyZXkzMCIsIGx3ZCA9IDAuMTUpLCAgI0JvcmRlciBsaW5lIGNvbG9yIGFuZCB3aWR0aCBvZiBlYWNoIGNlbGwuDQogICAgICAgICAgICAgICAgIHNob3dfY29sdW1uX25hbWVzID0gRkFMU0UsICAgICAgICAgICAgICAgICAgICNXaGV0aGVyIHRvIHNob3cgY29sdW1uIGxhYmVsaW5nLg0KICAgICAgICAgICAgICAgICBzaG93X3Jvd19uYW1lcyA9IEZBTFNFLCAgICAgICAgICAgICAgICAgICAgICAjV2hldGhlciB0byBzaG93IHJvdyBsYWJlbGluZy4NCiAgICAgICAgICAgICAgICAgI3Jvd19uYW1lc19ncCA9IGdwYXIoZm9udHNpemUgPSA0KSwgICAgICAgICAgI1VuY29tbWVudCB0byBzcGVjaWZ5IHJvdyBsYWJlbCBmb250IHNpemUuDQogICAgICAgICAgICAgICAgICNyb3dfbmFtZXNfc2lkZSA9ICJsZWZ0IiwgICAgICAgICAgICAgICAgICAgICNVbmNvbW1lbnQgdG8gc3BlY2lmeSByb3cgbGFiZWwgc2lkZS4NCiAgICAgICAgICAgICAgICAgY2x1c3RlcmluZ19kaXN0YW5jZV9jb2x1bW5zID0gInBlYXJzb24iLCAgICAgI1NldCBjbHVzdGVyaW5nIG1ldGhvZCBmb3IgY29sdW1uIGRlbmRyb2dyYW0uDQogICAgICAgICAgICAgICAgIGNsdXN0ZXJpbmdfZGlzdGFuY2Vfcm93cyA9ICJwZWFyc29uIiwgICAgICAgICNTZXQgY2x1c3RlcmluZyBtZXRob2QgZm9yIHJvdyBkZW5kcm9ncmFtLg0KICAgICAgICAgICAgICAgICByb3dfZGVuZF9yZW9yZGVyID0gRkFMU0UsICAgICAgICAgICAgICAgICAgICAjV2hldGhlciB0byBhcHBseSByb3cgZGVuZHJvZ3JhbSByZW9yZGVyaW5nLg0KICAgICAgICAgICAgICAgICBjb2x1bW5fZGVuZF9yZW9yZGVyID0gVFJVRSwgICAgICAgICAgICAgICAgICAjV2hldGhlciB0byBhcHBseSBjb2x1bW4gZGVuZHJvZ3JhbSByZW9yZGVyaW5nLg0KICAgICAgICAgICAgICAgICBzaG93X3Jvd19kZW5kID0gRkFMU0UsICAgICAgICAgICAgICAgICAgICAgICAjV2hldGhlciB0byBzaG93IHJvdyBkZW5kcm9ncmFtIGNsdXN0ZXJpbmcuDQogICAgICAgICAgICAgICAgIHNob3dfY29sdW1uX2RlbmQgPSBGQUxTRSwgICAgICAgICAgICAgICAgICAgICNXaGV0aGVyIHRvIHNob3cgY29sdW1uIGRlbmRyb2dyYW0gY2x1c3RlcmluZy4NCiAgICAgICAgICAgICAgICAgd2lkdGggPSB1bml0KDMsICJpbiIpLCAgICAgICAgICAgICAgICAgICAgICAgI1NldCBoZWF0bWFwIHdpZHRoLg0KICAgICAgICAgICAgICAgICBoZWlnaHQgPSB1bml0KDMuNSwgImluIiksICAgICAgICAgICAgICAgICAgICAjU2V0IGhlYXRtYXAgaGVpZ2h0Lg0KICAgICAgICAgICAgICAgICBoZWF0bWFwX2xlZ2VuZF9wYXJhbSA9IGxnZF9saXN0LCAgICAgICAgICAgICAjUmVmZXJlbmNlIG9iamVjdCBmb3IgbGVnZW5kIHBhcmFtZXRlcnMuDQogICAgICAgICAgICAgICAgIG5hbWUgPSAiWi1zY29yZSIpICAgICAgICAgICAgICAgICAgICAgICAgICAgICNTZXQgdGl0bGUuDQoNCmh0X21lcmdlID0gaHRfc2VsZWN0ZWRfbGFiZWwgKyByb3dBbm5vdGF0aW9uKG1hcmsgPSBmb28pDQpodF9tZXJnZSA9IGRyYXcoaHRfbWVyZ2UsIGhlYXRtYXBfbGVnZW5kX3NpZGUgPSAiYm90dG9tIiwgYWxpZ25faGVhdG1hcF9sZWdlbmQgPSAiaGVhdG1hcF9sZWZ0IikgI05vdGU6ICdhbGlnbl9oZWF0bWFwX2xlZ2VuZCcgPSAnaGVhdG1hcF9jZW50ZXInIHBvc2l0aW9uIGlzIG9mZnNldCBiZWNhdXNlIGhlYXRtYXAgaGFzIGJlZW4gbWVyZ2VkIHdpdGggJ3Jvd0Fubm90YXRpb24nLg0Kc3ZnKGZpbGVuYW1lID0gIjJEX0hlYXRtYXBfU2VjcmV0ZWRfQ29tcGFjdExhYmVsLnN2ZyIsIHdpZHRoID0gNC41LCBoZWlnaHQgPSA0LjUpDQpkZXYub2ZmKCkNCmBgYA0KDQoNCg0KDQoNCg==